el_pup_le
el_pup_le

Reputation: 12179

Getting a WCF endpoint http request context in an attribute class

I want to get the endpoint method request context inside the attribute class.

So if I had this endpoint

[Auth]
[WebInvoke(UriTemplate ="/post",
           Method = "POST",
           ResponseFormat = WebMessageFormat.Json,
           RequestFormat = WebMessageFormat.Json)]
public string CreatePost(var data)

And then in the class

public class Auth : Attribute
{

    public bool IsAuthorised()
    {
        // get the request then add something to the endpoint context

Upvotes: 0

Views: 297

Answers (1)

Navoneel Talukdar
Navoneel Talukdar

Reputation: 4598

Take a look at below WCF declaration.

[BasicHttpAuthorization(RequireSsl = true)]
[WebGet(UriTemplate = "")]
public IEnumerable Get()
{
 .....
}

So BasicHttpAuthorization implements Attribute

[AttributeUsage(AttributeTargets.Method)]
public class BasicHttpAuthorizationAttribute : Attribute
{
    bool requireSsl = true;

    public bool RequireSsl
    {
        get { return requireSsl; }
        set { requireSsl = value; }
    }
}

Now you can take a look at implementation of HttpOperationHandler.

1) If the user is not authenticated yet or provides the wrong credentials we return a HttpResponseException in the OnHandle method. We set the status code to 401. This creates the functionality, where the browser asks for a username/password and then automatically resends the request.

2) In ParseAuthHeader we get the username and password out of the request. You can then use this info with in your own way. For example with your own custom membership provider.

3) If the user can access this method, you create a GenericPrincipal and assign it to HttpContext.Current.User.

public class BasicHttpAuthorizationOperationHandler : HttpOperationHandler
{

    BasicHttpAuthorizationAttribute basicHttpAuthorizationAttribute;

    public BasicHttpAuthorizationOperationHandler(BasicHttpAuthorizationAttribute authorizeAttribute)
        : base("response")
    {
        basicHttpAuthorizationAttribute = authorizeAttribute;
    }

    protected override HttpRequestMessage OnHandle(HttpRequestMessage input)
    {
        if (Authenticate(input))
        {
            return input;
        }
        else
        {
            var challengeMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized);
            challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
            throw new HttpResponseException(challengeMessage);
        }
    }

    private bool Authenticate(HttpRequestMessage input)
    {
        if (basicHttpAuthorizationAttribute.RequireSsl && !HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.IsLocal) return false;

        if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization")) return false;

        string authHeader =  HttpContext.Current.Request.Headers["Authorization"];

        IPrincipal principal;
        if (TryGetPrincipal(authHeader, out principal))
        {
            HttpContext.Current.User = principal;
            return true;
        }
        return false;
    }

    private bool TryGetPrincipal(string authHeader, out IPrincipal principal)
    {
        var creds = ParseAuthHeader(authHeader);
        if (creds != null)
        {
            if (TryGetPrincipal(creds[0], creds[1], out principal)) return true;
        }

        principal = null;
        return false;
    }

    private string[] ParseAuthHeader(string authHeader)
    {
        // Check this is a Basic Auth header
        if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic")) return null;

        // Pull out the Credentials with are seperated by ':' and Base64 encoded
        string base64Credentials = authHeader.Substring(6);
        string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });

        if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[0])) return null;

        // Okay this is the credentials
        return credentials;
    }

    private bool TryGetPrincipal(string userName, string password, out IPrincipal principal)
    {
        // this is the method that does the authentication
        // you can replace this with whatever logic you'd use, but proper separation would put the

        if (userName.Equals("test") && password.Equals("test"))
        {                
            principal = new GenericPrincipal(new GenericIdentity(userName), new string[] {"Admin", "User"});

            return true;
        }
        else
        {
            principal = null;
            return false;
        }
    }
}

Upvotes: 1

Related Questions