Question

I cannot seem to login when I call -- api/values. the client-end throws "Authorization has been denied for this request." message.

I tried debugging the basicAuthHandler class but it does not seem to be crashing anywhere, so I am little stuck and how can I pin point the issue.

could it be my validate method or constructor in my global.aspx?

public class BasicAuthMessageHandler : DelegatingHandler
  {

    private const string BasicAuthResponseHeader = "WWW-Authenticate";
    private const string BasicAuthResponseHeaderValue = "Basic";

    //[Inject]
    //public iUser Repository { get; set; }

    // private readonly iUser Repository;

    private readonly iUser Repository = new User();

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        AuthenticationHeaderValue authValue = request.Headers.Authorization;
        if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter))
        {
            api_login parsedCredentials = ParseAuthorizationHeader(authValue.Parameter);
            if (parsedCredentials != null)
            {
                IPrincipal principal;
                if (TryGetPrincipal(parsedCredentials.username, parsedCredentials.password, out principal))
                {
                    Thread.CurrentPrincipal = principal;
                    //request.GetRequestContext().Principal = principal;
                }
            }
        }

        return base.SendAsync(request, cancellationToken).ContinueWith(task =>
        {
            var response = task.Result;
            if (response.StatusCode == HttpStatusCode.Unauthorized && !response.Headers.Contains(BasicAuthResponseHeader))
            {
                response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
            }

            return response;
        });
    }

    private api_login ParseAuthorizationHeader(string authHeader)
    {
        string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(authHeader)).Split(new[] { ':' });
        if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[1])) return null;

        return new api_login()
        {
            username = credentials[0],
            password = credentials[1],
        };
    }

    private bool TryGetPrincipal(string userName, string password, out IPrincipal principal)
    {
        // this is the method that authenticates against my repository (in this case, hard coded)
        // you can replace this with whatever logic you'd use, but proper separation would put the
        // data access in a repository or separate layer/library.
        api_login user = Repository.Validate2(userName, password);

        if (user.username != null)
        {
            // once the user is verified, assign it to an IPrincipal with the identity name and applicable roles
            principal = new GenericPrincipal(new GenericIdentity(user.username), null);

        }

        principal = null;
        return false;
    }
  }
}

global.aspx:

 GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());

Any help would be very much appreciated. Thank you.

Was it helpful?

Solution

I think you didn't handle the response correctly in your code, I created a MessageHandler for Basic Authentication base on your code, hope it'll give you an good idea (I didn't test it), see below:

 public class BasicAuthMessageHandler : DelegatingHandler
    {
        private const string BasicAuthResponseHeader = "WWW-Authenticate";
        private const string BasicAuthResponseHeaderValue = "Basic";
        //[Inject]
        //public iUser Repository { get; set; }
        // private readonly iUser Repository;
        private readonly iUser Repository = new User();

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            AuthenticationHeaderValue authValue = request.Headers.Authorization;

            if (authValue == null || authValue.Scheme != BasicAuthResponseHeaderValue)
            {
                return Unauthorized(request);
            }
            string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(authValue.Parameter)).Split(new[] { ':' });
            if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[1]))
            {
                return Unauthorized(request);
            }
            api_login user = Repository.Validate2(credentials[0], credentials[1]);
            if (user == null)
            {
                return Unauthorized(request);
            }
            IPrincipal principal = new GenericPrincipal(new GenericIdentity(user.username, BasicAuthResponseHeaderValue), null);
            Thread.CurrentPrincipal = principal;
            HttpContext.Current.User = principal;

            return base.SendAsync(request, cancellationToken);
        }

        private Task<HttpResponseMessage> Unauthorized(HttpRequestMessage request)
        {
            var response = request.CreateResponse(HttpStatusCode.Unauthorized);
            response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue); 
            var task = new TaskCompletionSource<HttpResponseMessage>(); 
            task.SetResult(response); 
            return task.Task;
        }

    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top