29

I'm sure this is possible but not certain how to achieve. I have an OWIN OAUTH implementation that currently accepts the users Username and Password and authenticates them against a database. I would like to extend this to pass in a SmartCard Uid to support single sign-on with a SmartCard.

Can I pass in additional parameters in the OWIN login and if so how? The basic premise is that a user can login with a username/password combination Or a SmartCard uid (if passing a SmartCard uid and that is found in the database then the application will log the user in)

I am currently passing in username, password and grant_type and I would like to add uid to that list and pick that up in the my AuthorizationServiceProvider.

I can see UserName, Password and ClientId on the OAuthGrantResourceOwnerCredentialsContext but I cannot see any other properties that would support what I am trying to achieve.

This is what I currently have in my service provider

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        var user = await this._userService.FindUser(context.UserName, context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
        identity.AddClaim(new Claim(ClaimTypes.Sid, user.Id.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
        identity.AddClaim(new Claim("sub", context.UserName));

        var secretKeyBytes = Encoding.UTF8.GetBytes(user.PasswordHash);
        var props =
            new AuthenticationProperties(
                new Dictionary<string, string>
                    {
                        { "dm:appid", user.Id.ToString() },
                        { "dm:apikey", Convert.ToBase64String(secretKeyBytes) }
                    });

        var ticket = new AuthenticationTicket(identity, props);
        context.Validated(ticket);
    }

I want to be able to get Uid from the context as well but cannot see anyway of achieving this, any help is greatly appreciated.

Neil Stevens
  • 3,534
  • 6
  • 42
  • 71

1 Answers1

59

You have to implement ValidateClientAuthentication if you haven't done so.

This is the place where you should validate your client. In this methods you will do some sort of validation of your client and set the objects/variable which can be read in GrantResourceOwnerCredentials.

Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)

receives an OAuthValidateClientAuthenticationContext which contains the additional field(s) you're passing when POSTing to your authorization server.

enter image description here

In the picture above I've added an extra parameter uid in 4th position.

Before you validate your context:

context.Validated(clientId);

you can set your variable/object:

string uid = context.Parameters.Where(f => f.Key == "uid").Select(f => f.Value).SingleOrDefault()[0];
context.OwinContext.Set<string>("SmartCard", uid);

Now, in your GrantResourceOwnerCredentials you can simply read the value and use it:

string uid = context.OwinContext.Get<string>("SmartCard");

If you want to find out more you can have a look at this github repository where I pass an object:

context.OwinContext.Set<ApplicationClient>("oauth:client", client);

If you download the whole solution you can test it with a javascript/jquery client.

UPDATE:

You would pass an additional parameter (IE: uid) in your http POST request:

Vanilla Js:

var request = new XMLHttpRequest();
request.open('POST', oAuth.AuthorizationServer, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
request.setRequestHeader('Authorization', 'Basic ' + authorizationBasic);
request.setRequestHeader('Accept', 'application/json');
request.send("username=John&password=Smith&grant_type=password&uid=b17ac911-4cf1-4a3e-84a9-beac7b9da157");

jQuery:

$.ajax({
        type: 'POST',
        url: oAuth.AuthorizationServer,
        data: { username: 'John', password: 'Smith', grant_type: 'password', uid: 'b17ac911-4cf1-4a3e-84a9-beac7b9da157' },
        dataType: "json",
        contentType: 'application/x-www-form-urlencoded; charset=utf-8',
        xhrFields: {
        withCredentials: true
    },
        // crossDomain: true,
        headers: {
                'Authorization': 'Basic ' + authorizationBasic
    }
});
LeftyX
  • 35,328
  • 21
  • 132
  • 193
  • Perfect thanks, made a slight change to reading the parameter out in case it is not passed in the first place, other than that is exactly what i was looking for, thanks – Neil Stevens Jul 19 '15 at 19:23
  • Glad I've helped Neil. – LeftyX Jul 20 '15 at 12:53
  • @LeftyX Hi. i am trying to write my own oauth server using client_credentials. But i am stuck in-between. can i get some help? https://github.com/koushiksaha89/oauthserver – Koushik Saha May 04 '16 at 13:33
  • 1
    @user3132179 I know this has been a while, but what specifically is your problem, I would suggest adding a question and detailing your problem where you may then be likely to get an answer and possible solution – Neil Stevens Jan 12 '17 at 13:33
  • this question and answer save my life! just curious is there any official doc out there explaining this? – zeroflaw Mar 13 '18 at 01:37
  • 1
    @zeroflaw: Probably, but I couldn't find it. There are a good number of interesting blogs worth reading on the subject. [BitOfTech](http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/) is the best one I had found. Cheers. – LeftyX Mar 13 '18 at 08:57
  • "Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) receives an OAuthValidateClientAuthenticationContext which contains the additional field(s) your passing when POSTing to your authorization server". I'm kinda lost about where you are actually adding the additional field. Uid is not defined anywhere in your code. – SamyCode Mar 16 '18 at 21:34
  • @SamyCode: Check my updated answer and the [code](https://github.com/Leftyx/OwinWebApiBearerToken) in github, please. Cheers. – LeftyX Mar 17 '18 at 10:40
  • Now I see everything and I was able to make it work. You saved my day. Thank you. – SamyCode Mar 19 '18 at 14:47