0

I want to change the way the default bearer token system works.

I want to login to the webAPI providing the username, password, and mac address of the device. Like so.

Content-Type: application/x-www-form-urlencoded    
username=test&password=P@ssword&grant_type=password&client_id=android&device_info=MAC_Address

I then want the API to provide me with a Refresh Token. This token will be valid for say 7 days and will allow for me to get a new access token. However in the refresh token I want to save / embed the security stamp of the users password in the token along with the extirpation date. This way I can check the security stamp when a new access token is requested. (solves password changing scenario)

My access token only needs to store the bare amount of information for it to work. I don't require that the access token store anything specific. I would like to keep it as small as possible. When it expires I will simply request a new access token using my refresh token.

Now I have tried to implement the above but have got my self heavily confused about what to implement where. Here's what i have got.

Step 1: The Startup.Auth.cs

//Configure the application for OAuth based flow
PublicClientId = "self";

OAuthOptions = new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,
    TokenEndpointPath = new PathString("/Token"),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),

    Provider = new SimpleAuthorizationServerProvider(),
    RefreshTokenProvider = new SimpleRefreshTokenProvider(),           
    AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20)
};

Now in here I already have some questions. I want to have two providers, one which handles Refresh Tokens and one that handles Access Tokens. Which providers do I need to set? because I see there is also one called AccessTokenProvider = then what is Provider = for?

Step 2: The RereshTokenProvider. This is what I have so far:

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
    {
        //Used to store all the refresh tokens
        public static ConcurrentDictionary<string, AuthenticationTicket> RefreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        public Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            var guid = Guid.NewGuid().ToString("N");

            //copy properties and set the desired lifetime of refresh token
            var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
            {
                IssuedUtc = context.Ticket.Properties.IssuedUtc,
                ExpiresUtc = DateTime.UtcNow.AddDays(7)
            };

           //TODO: get mac address from the request headers??
           //TODO: save the mac address to db along with user and date       

            var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);
            RefreshTokens.TryAdd(guid, refreshTokenTicket);

            context.SetToken(guid);
            return Task.FromResult<object>(null);
        }

        public Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            AuthenticationTicket ticket;

            if (RefreshTokens.TryRemove(context.Token, out ticket))
            {
                context.SetTicket(ticket);
            }
            return Task.FromResult<object>(null);
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }
    }

Now if i understand correctly. The purpose of the SimpleRefreshTokenProvider is to build up a RefreshToken and to the validate it when the api receives a request with one in it?

Step 3: SimpleAuthorizationServerProvider. This is what I have so far. but I have a feeling this is where I have gone wrong. Or im getting confused, What is the purpose of this class? Is it not to validate the AccessToken?

 public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
        {
            public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                // Not concerned about clients yet
                context.Validated();
            }        

            public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            {
                // validate user credentials 
                var userManager = context.OwinContext.GetUserManager<FskUserManager>();
                FskUser user = await userManager.FindAsync(context.UserName, context.Password);
                if (user == null)
                {
                    context.SetError("invalid_grant", "The user name or password is incorrect.");
                    return;
                }          

                // create identity
                ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
                      OAuthDefaults.AuthenticationType);
                ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                    CookieAuthenticationDefaults.AuthenticationType);

                //Set properties of the token
                // create metadata to pass on to refresh token provider
                AuthenticationProperties properties = new AuthenticationProperties(new Dictionary<string, string>
                {
                    {"userName", user.UserName}               
                });

                AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
                context.Validated(ticket);
                context.Request.Context.Authentication.SignIn(cookiesIdentity);
            }       

            public override async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
            {
                string originalClient;
                context.Ticket.Properties.Dictionary.TryGetValue("as:client_id", out originalClient);

                var currentClient = context.ClientId;           

                // chance to change authentication ticket for refresh token requests
                var newId = new ClaimsIdentity(context.Ticket.Identity);
                newId.AddClaim(new Claim("newClaim", "refreshToken"));

                var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);
                context.Validated(newTicket);
            }
        }

Please what am I missing here?

Jayendran
  • 9,638
  • 8
  • 60
  • 103
Zapnologica
  • 22,170
  • 44
  • 158
  • 253
  • About Mac Address - have you accomplished to get it in someway? As far as I know it's not possible (except specific cases). Look here http://stackoverflow.com/questions/3309122/how-can-i-get-a-mac-address-from-an-http-request. – Artiom Apr 17 '15 at 12:22
  • The mac address is simply added by the client software as a parameter in header. It has nothing to do with http or api. I simply want to log which device a user logged in on. – Zapnologica Apr 18 '15 at 14:37

0 Answers0