Quantcast
Channel: ASP.Net Web API – Bit of Technology
Viewing all 37 articles
Browse latest View live

Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin

$
0
0

After my previous Token Based Authentication post I’ve received many requests to add OAuth Refresh Tokens to the OAuth Resource Owner Password Credentials flow which I’m currently using in the previous tutorial. To be honest adding support for refresh tokens adds a noticeable level of complexity to your Authorization Server. As well most of the available resources on the net don’t provide the full picture of how to implement this by introducing clients nor how to persist the refresh tokens into database.

So I’ve decided to write a detailed post with live demo application which resumes what we’ve built in the previous posts, so I recommend you to read part 1 at least to follow along with this post. This detailed post will cover adding Clients, persisting refresh tokens, dynamically configuring refresh tokens expiry dates, and revoking refresh tokens.

You can check the demo application, play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

AngularJS OAuth Refresh Tokens

Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin

Before start into the implementation I would like to discuss when and how refresh tokens should be used, and what is the database structure needed to implement a complete solution.

Using Refresh Tokens

The idea of using refresh token is to issue short lived access token at the first place then use the refresh token to obtain new access token and so on, so the user needs to authenticate him self by providing username and password along with client info (we’ll talk about clients later in this post), and if the information provided is valid a response contains a short lived access token is obtained along with long lived refresh token (This is not an access token, it is just identifier to the refresh token). Now once the access token expires we can use the refresh token identifier to try to obtain another short lived access token and so on.

But why we are adding this complicity, why not to issue long lived access tokens from the first place?

In my own opinion there are three main benefits to use refresh tokens which they are:

  1. Updating access token content: as you know the access tokens are self contained tokens, they contain all the claims (Information) about the authenticated user once they are generated, now if we issue a long lived token (1 month for example) for a user named “Alex” and enrolled him in role “Users” then this information get contained on the token which the Authorization server generated. If you decided later on (2 days after he obtained the token) to add him to the “Admin” role then there is no way to update this information contained in the token generated, you need to ask him to re-authenticate him self again so the Authorization server add this information to this newly generated access token, and this not feasible on most of the cases. You might not be able to reach users who obtained long lived access tokens. So to overcome this issue we need to issue short lived access tokens (30 minutes for example) and use the refresh token to obtain new access token, once you obtain the new access token, the Authorization Server will be able to add new claim for user “Alex” which assigns him to “Admin” role once the new access token being generated.
  2. Revoking access from authenticated users: Once the user obtains long lived access token he’ll be able to access the server resources as long as his access token is not expired, there is no standard way to revoke access tokens unless the Authorization Server implements custom logic which forces you to store generated access token in database and do database checks with each request. But with refresh tokens, a system admin can revoke access by simply deleting the refresh token identifier from the database so once the system requests new access token using the deleted refresh token, the Authorization Server will reject this request because the refresh token is no longer available (we’ll come into this with more details).
  3. No need to store or ask for username and password: Using refresh tokens allows you to ask the user for his username and password only one time once he authenticates for the first time, then Authorization Server can issue very long lived refresh token (1 year for example) and the user will stay logged in all this period unless system admin tries to revoke the refresh token. You can think of this as a way to do offline access to server resources, this can be useful if you are building an API which will be consumed by front end application where it is not feasible to keep asking for username/password frequently.

Refresh Tokens and Clients

In order to use refresh tokens we need to bound the refresh token with a Client, a Client means the application the is attempting communicate with the back-end API, so you can think of it as the software which is used to obtain the token. Each Client should have Client Id and Secret, usually we can obtain the Client Id/Secret once we register the application with the back-end API.

The Client Id is a unique public information which identifies your application among other apps using the same back-end API. The client id can be included in the source code of your application, but the client secret must stay confidential so in case we are building JavaScript apps there is no need to include the secret in the source code because there is no straight way to keep this secret confidential on JavaScript application. In this case we’ll be using the client Id only for identifying which client is requesting the refresh token so it can be bound to this client.

In our case I’ve identified clients to two types (JavaScript – Nonconfidential) and (Native-Confidential) which means that for confidential clients we can store the client secret in confidential way (valid for desktop apps, mobile apps, server side web apps) so any request coming from this client asking for access token should include the client id and secret.

Bounding the refresh token to a client is very important, we do not want any refresh token generated from our Authorization Server to be used in another client to obtain access token. Later we’ll see how we will make sure that refresh token is bounded to the same client once it used to generate new access token.

Database structure needed to support OAuth Refresh Tokens

It is obvious that we need to store clients which will communicate with our back-end API in persistent medium, the schema for Clients table will be as the image below:

OAuth 2.0 Clients

The Secret column is hashed so anyone has an access to the database will not be able to see the secrets, the Application Type column with value (1) means it is Native – Confidential client which should send the secret once the access token is requested.

The Active column is very useful; if the system admin decided to deactivate this client, so any new requests asking for access token from this deactivated client will be rejected. The Refresh Token Life Time column is used to set when the refresh token (not the access token) will expire in minutes so for the first client it will expire in 10 days, it is nice feature because now you can control the expiry for refresh tokens for each client.

Lastly the Allowed Origin column is used configure CORS and to set “Access-Control-Allow-Origin” on the back-end API. It is only useful for JavaScript applications using XHR requests, so in my case I’ m setting the allowed origin for client id “ngAuthApp” to origin “http://ngauthenticationweb.azurewebsites.net/” and this turned out to be very useful, so if any malicious user obtained my client id from my JavaScript app which is very trivial to do, he will not be able to use this client to build another JavaScript application using the same client id because all preflighted  requests will fail and return 405 HTTP status (Method not allowed) All XHR requests coming for his JavaScript app will be from different domain. This is valid for JavaScript application types only, for other application types you can set this to “*”.

Note: For testing the API the secret for client id “consoleApp” is “123@abc”.

Now we need to store the refresh tokens, this is important to facilitate the management for refresh tokens, the schema for Refresh Tokens table will be as the image below:

Refresh Tokens

The Id column contains hashed value of the refresh token id, the API consumer will receive and send the plain refresh token Id. the Subject column indicates to which user this refresh token belongs, and the same applied for Client Id column, by having this columns we can revoke the refresh token for a certain user on certain client and keep the other refresh tokens for the same user obtained by different clients available.

The Issued UTC and Expires UTC columns are for displaying purpose only, I’m not building my refresh tokens expiration logic based on these values.

Lastly the Protected Ticket column contains magical signed string which contains a serialized representation for the ticket for specific user, in other words it contains all the claims and ticket properties for this user. The Owin middle-ware will use this string to build the new access token auto-magically (We’ll see how this take place later in this post).

Now I’ll walk you through implementing the refresh tokens, as I stated before you can read the previous post to be able to follow along with me:

Step 1: Add the new Database Entities

Add new folder named “Entities”, inside the folder you need to define 2 classes named “Client” and “RefreshToken”, the definition for classes as the below:

public class Client
    {
        [Key] 
        public string Id { get; set; }
        [Required]
        public string Secret { get; set; }
        [Required]
        [MaxLength(100)]
        public string Name { get; set; }
        public ApplicationTypes ApplicationType { get; set; }
        public bool Active { get; set; }
        public int RefreshTokenLifeTime { get; set; }
        [MaxLength(100)]
        public string AllowedOrigin { get; set; }
    }

public class RefreshToken
    {
        [Key]
        public string Id { get; set; }
        [Required]
        [MaxLength(50)]
        public string Subject { get; set; }
        [Required]
        [MaxLength(50)]
        public string ClientId { get; set; }
        public DateTime IssuedUtc { get; set; }
        public DateTime ExpiresUtc { get; set; }
        [Required]
        public string ProtectedTicket { get; set; }
    }

Then we need to add simple Enum which defined the Application Type, so add class named “Enum” inside the “Models” folder as the code below:

public enum ApplicationTypes
    {
        JavaScript = 0,
        NativeConfidential = 1
    };

To make this entities available on the DbContext, open file “AuthContext” and paste the code below:

public class AuthContext : IdentityDbContext<IdentityUser>
    {
        public AuthContext()
            : base("AuthContext")
        {
     
        }

        public DbSet<Client> Clients { get; set; }
        public DbSet<RefreshToken> RefreshTokens { get; set; }
    }

Step 2: Add new methods to repository class

The methods I’ll add now will add support for manipulating the tables we’ve added, they are self explanatory methods and there is nothing special about them, so open file “AuthRepository” and paste the code below:

public Client FindClient(string clientId)
        {
            var client = _ctx.Clients.Find(clientId);

            return client;
        }

        public async Task<bool> AddRefreshToken(RefreshToken token)
        {

           var existingToken = _ctx.RefreshTokens.Where(r => r.Subject == token.Subject && r.ClientId == token.ClientId).SingleOrDefault();

           if (existingToken != null)
           {
             var result = await RemoveRefreshToken(existingToken);
           }
          
            _ctx.RefreshTokens.Add(token);

            return await _ctx.SaveChangesAsync() > 0;
        }

        public async Task<bool> RemoveRefreshToken(string refreshTokenId)
        {
           var refreshToken = await _ctx.RefreshTokens.FindAsync(refreshTokenId);

           if (refreshToken != null) {
               _ctx.RefreshTokens.Remove(refreshToken);
               return await _ctx.SaveChangesAsync() > 0;
           }

           return false;
        }

        public async Task<bool> RemoveRefreshToken(RefreshToken refreshToken)
        {
            _ctx.RefreshTokens.Remove(refreshToken);
             return await _ctx.SaveChangesAsync() > 0;
        }

        public async Task<RefreshToken> FindRefreshToken(string refreshTokenId)
        {
            var refreshToken = await _ctx.RefreshTokens.FindAsync(refreshTokenId);

            return refreshToken;
        }

        public List<RefreshToken> GetAllRefreshTokens()
        {
             return  _ctx.RefreshTokens.ToList();
        }

Step 3: Validating the Client Information

Now we need to implement the logic responsible to validate the client information sent one the application requests an access token or uses a refresh token to obtain new access token, so open file “SimpleAuthorizationServerProvider” and paste the code below:

public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {

            string clientId = string.Empty;
            string clientSecret = string.Empty;
            Client client = null;

            if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
            {
                context.TryGetFormCredentials(out clientId, out clientSecret);
            }

            if (context.ClientId == null)
            {
                //Remove the comments from the below line context.SetError, and invalidate context 
                //if you want to force sending clientId/secrects once obtain access tokens. 
                context.Validated();
                //context.SetError("invalid_clientId", "ClientId should be sent.");
                return Task.FromResult<object>(null);
            }

            using (AuthRepository _repo = new AuthRepository())
            {
                client = _repo.FindClient(context.ClientId);
            }

            if (client == null)
            {
                context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId));
                return Task.FromResult<object>(null);
            }

            if (client.ApplicationType == Models.ApplicationTypes.NativeConfidential)
            {
                if (string.IsNullOrWhiteSpace(clientSecret))
                {
                    context.SetError("invalid_clientId", "Client secret should be sent.");
                    return Task.FromResult<object>(null);
                }
                else
                {
                    if (client.Secret != Helper.GetHash(clientSecret))
                    {
                        context.SetError("invalid_clientId", "Client secret is invalid.");
                        return Task.FromResult<object>(null);
                    }
                }
            }

            if (!client.Active)
            {
                context.SetError("invalid_clientId", "Client is inactive.");
                return Task.FromResult<object>(null);
            }

            context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin);
            context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());

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

By looking at the code above you will notice that we are doing the following validation steps:

  1. We are trying to get the Client id and secret from the authorization header using a basic scheme so one way to send the client_id/client_secret is to base64 encode the (client_id:client_secret) and send it in the Authorization header. The other way is to sent the client_id/client_secret as “x-www-form-urlencoded”. In my case I’m supporting the both approaches so client can set those values using any of the two available options.
  2. We are checking if the consumer didn’t set client information at all, so if you want to enforce setting the client id always then you need to invalidate the context. In my case I’m allowing to send requests without client id for the sake of keeping old post and demo working correctly.
  3. After we receive the client id we need to check our database if the client is already registered with our back-end API, if it is not registered we’ll invalidate the context and reject the request.
  4. If the client is registered we need to check his application type, so if it was “JavaScript – Non Confidential” client we’ll not check or ask for the secret. If it is Native – Confidential app then the client secret is mandatory and it will be validated against the secret stored in the database.
  5. Then we’ll check if the client is active, if it is not the case then we’ll invalidate the request.
  6. Lastly we need to store the client allowed origin and refresh token life time value on the Owin context so it will be available once we generate the refresh token and set its expiry life time.
  7. If all is valid we mark the context as valid context which means that client check has passed and the code flow can proceed to the next step.

Step 4: Validating the Resource Owner Credentials

Now we need to modify the method “GrantResourceOwnerCredentials” to validate that resource owner username/password is correct and bound the client id to the access token generated, so open file “SimpleAuthorizationServerProvider” and paste the code below:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {

            var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");

            if (allowedOrigin == null) allowedOrigin = "*";

            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

            using (AuthRepository _repo = new AuthRepository())
            {
                IdentityUser user = await _repo.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.Name, context.UserName));
            identity.AddClaim(new Claim("sub", context.UserName));
            identity.AddClaim(new Claim("role", "user"));

            var props = new AuthenticationProperties(new Dictionary<string, string>
                {
                    { 
                        "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
                    },
                    { 
                        "userName", context.UserName
                    }
                });

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

        }

 public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {
            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }

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

By looking at the code above you will notice that we are doing the following:

  1. Reading the allowed origin value for this client from the Owin context, then we use this value to add the header “Access-Control-Allow-Origin” to Owin context response, by doing this and for any JavaScript application we’ll prevent using the same client id to build another JavaScript application hosted on another domain; because the origin for all requests coming from this app will be from a different domain and the back-end API will return 405 status.
  2. We’ll check the username/password for the resource owner if it is valid, and if this is the case we’ll generate set of claims for this user along with authentication properties which contains the client id and userName, those properties are needed for the next steps.
  3. Now the access token will be generated behind the scenes when we call “context.Validated(ticket)”

Step 5: Generating the Refresh Token and Persisting it

Now we need to generate the Refresh Token and Store it in our database inside the table “RefreshTokens”, to do the following we need to add new class named “SimpleRefreshTokenProvider” under folder “Providers” which implements the interface “IAuthenticationTokenProvider”, so add the class and paste the code below:

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
    {

        public async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            var clientid = context.Ticket.Properties.Dictionary["as:client_id"];

            if (string.IsNullOrEmpty(clientid))
            {
                return;
            }

            var refreshTokenId = Guid.NewGuid().ToString("n");

            using (AuthRepository _repo = new AuthRepository())
            {
                var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime"); 
               
                var token = new RefreshToken() 
                { 
                    Id = Helper.GetHash(refreshTokenId),
                    ClientId = clientid, 
                    Subject = context.Ticket.Identity.Name,
                    IssuedUtc = DateTime.UtcNow,
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime)) 
                };

                context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
                context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
                
                token.ProtectedTicket = context.SerializeTicket();

                var result = await _repo.AddRefreshToken(token);

                if (result)
                {
                    context.SetToken(refreshTokenId);
                }
             
            }
        }
 }

As you notice this class implements the interface “IAuthenticationTokenProvider” so we need to add our refresh token generation logic inside method “CreateAsync”, and by looking at the code above we can notice the below:

  1. We are generating a unique identifier for the refresh token, I’m using Guid here which is enough for this or you can use your own unique string generation algorithm.
  2. Then we are reading the refresh token life time value from the Owin context where we set this value once we validate the client, this value will be used to determine how long the refresh token will be valid for, this should be in minutes.
  3. Then we are setting the IssuedUtc, and ExpiresUtc values for the ticket, setting those properties will determine how long the refresh token will be valid for.
  4. After setting all context properties we are calling method “context.SerializeTicket();” which will be responsible to serialize the ticket content and we’ll be able to store this magical serialized string on the database.
  5. After this we are building a token record which will be saved in RefreshTokens table, note that I’m checking that the token which will be saved on the database is unique for this Subject (User) and the Client, if it not unique I’ll delete the existing one and store new refresh token. It is better to hash the refresh token identifier before storing it, so if anyone has access to the database he’ll not see the real refresh tokens.
  6. Lastly we will send back the refresh token id (without hashing it) in the response body.

The “SimpleRefreshTokenProvider” class should be set along with the “OAuthAuthorizationServerOptions”, so open class “Startup” and replace the code used to set “OAuthAuthorizationServerOptions” in method “ConfigureOAuth” with the code below, notice that we are setting the access token life time to a short period now (30 minutes) instead of 24 hours.

OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() {
            
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                Provider = new SimpleAuthorizationServerProvider(),
                RefreshTokenProvider = new SimpleRefreshTokenProvider()
            };

Once this is done we we can now test obtaining refresh token and storing it in the database, to do so open your favorite REST client and I’ll use PostMan to compose the POST request against the endpoint http://ngauthenticationapi.azurewebsites.net/token the request will be as the image below:

Generate Refresh Token Request

What worth mentioning here that we are setting the client_id parameter in the request body, and once the “/token” end point receives this request it will go through all the validation we’ve implemented in method “ValidateClientAuthentication”, you can check how the validation will take place if we set the client_id to “consoleApp”  and how the client_secret is mandatory and should be provided with this request because the application type for this client is “Native-Confidential”.

As well by looking at the response body you will notice that we’ve obtained a “refresh_token” which should be used to obtain new access token (we’ll see this later in this post) this token is bounded to user “Razan” and for Client “ngAuthApp”. Note that the “expires_in” value is related to the access token not the refresh token, this access token will expires in 30 mins.

Step 6: Generating an Access Token using the Refresh Token

Now we need to implement the logic needed once we receive the refresh token so we can generate a new access token, to do so open class “SimpleRefreshTokenProvider”  and implement the code below in method “ReceiveAsync”:

public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {

            var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

            string hashedTokenId = Helper.GetHash(context.Token);

            using (AuthRepository _repo = new AuthRepository())
            {
                var refreshToken = await _repo.FindRefreshToken(hashedTokenId);

                if (refreshToken != null )
                {
                    //Get protectedTicket from refreshToken class
                    context.DeserializeTicket(refreshToken.ProtectedTicket);
                    var result = await _repo.RemoveRefreshToken(hashedTokenId);
                }
            }
        }

What we’ve implemented in this method is the below:

  1. We need to set the “Access-Control-Allow-Origin” header by getting the value from Owin Context, I’ve spent more than 1 hour figuring out why my requests to issue access token using a refresh token returns 405 status code and it turned out that we need to set this header in this method because the method “GrantResourceOwnerCredentials” where we set this header is never get executed once we request access token using refresh tokens (grant_type=refresh_token).
  2. We get the refresh token id from the request, then hash this id and look for this token using the hashed refresh token id in table “RefreshTokens”, if the refresh token is found, we will use the magical signed string which contains a serialized representation for the ticket to build the ticket and identities for the user mapped to this refresh token.
  3. We’ll remove the existing refresh token from tables “RefreshTokens” because in our logic we are allowing only one refresh token per user and client.

Now the request context contains all the claims stored previously for this user, we need to add logic which allows us to issue new claims or updating existing claims and contain them into the new access token generated before sending it to the user, to do so open class “SimpleAuthorizationServerProvider” and implement method “GrantRefreshToken” using the code below:

public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
        {
            var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
            var currentClient = context.ClientId;

            if (originalClient != currentClient)
            {
                context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
                return Task.FromResult<object>(null);
            }

            // Change auth ticket for refresh token requests
            var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
            newIdentity.AddClaim(new Claim("newClaim", "newValue"));

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

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

What we’ve implement above is simple and can be explained in the points below:

  1. We are reading the client id value from the original ticket, this is the client id which get stored in the magical signed string, then we compare this client id against the client id sent with the request, if they are different we’ll reject this request because we need to make sure that the refresh token used here is bound to the same client when it was generated.
  2. We have the chance now to add new claims or remove existing claims, this was not achievable without refresh tokens, then we call “context.Validated(newTicket)” which will generate new access token and return it in the response body.
  3. Lastly after this method executes successfully, the flow for the code will hit method “CreateAsync” in class “SimpleRefreshTokenProvider” and a new refresh token is generated and returned in the response along with the new access token.

To test this out we need to issue HTTP POST request to the endpoint http://ngauthenticationapi.azurewebsites.net/token the request will be as the image below:

Generate Access Token Request

Notice how we set the “grant_type” to “refresh_token” and passed the “refresh_token” value and client id with the request, if all went successfully we’ll receive a new access token and refresh token.

Step 7: Revoking Refresh Tokens

The idea here is simple, all you need to do is to delete the refresh token record from table “RefreshTokens” and once the user tries to request new access token using the deleted refresh token it will fail and he needs to authenticate again using his username/password in order to obtain new access token and refresh token. By having this feature your system admin can have control on how to revoke access from logged in users.

To do this we need to add new controller named “RefreshTokensController” under folder “Controllers” and paste the code below:

[RoutePrefix("api/RefreshTokens")]
    public class RefreshTokensController : ApiController
    {

        private AuthRepository _repo = null;

        public RefreshTokensController()
        {
            _repo = new AuthRepository();
        }

        [Authorize(Users="Admin")]
        [Route("")]
        public IHttpActionResult Get()
        {
            return Ok(_repo.GetAllRefreshTokens());
        }

        //[Authorize(Users = "Admin")]
        [AllowAnonymous]
        [Route("")]
        public async Task<IHttpActionResult> Delete(string tokenId)
        {
            var result = await _repo.RemoveRefreshToken(tokenId);
            if (result)
            {
                return Ok();
            }
            return BadRequest("Token Id does not exist");
            
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _repo.Dispose();
            }

            base.Dispose(disposing);
        }
    }

Nothing special implemented here, we only have 2 actions which lists all the stored refresh tokens on the database, and another method which accepts a query string named “tokeId”, this should contains the hashed value of the refresh token, this method will be used to delete/revoke refresh tokens.

For the sake of the demo, I’ve authorized only user named “Admin” to execute the “Get” method and obtain all refresh tokens, as well I’ve allowed anonymous access for the “Delete” method so you can try to revoke your own refresh tokens, on production you need to secure this end point.

To hash your refresh tokens you have to use the helper class below, so add new class named “Helper” and paste the code below:

public static string GetHash(string input)
        {
            HashAlgorithm hashAlgorithm = new SHA256CryptoServiceProvider();
       
            byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(input);

            byte[] byteHash = hashAlgorithm.ComputeHash(byteValue);

            return Convert.ToBase64String(byteHash);
        }

So to test this out and revoke a refresh token we need to issue a DELETE request to the following end point “http://ngauthenticationapi.azurewebsites.net/api/refreshtokens“, the request will be as the image below:

Revoke Refresh Token

Once the refresh token has been removed, if the user tries to use it he will fail obtaining new access token until he authenticate again using username/password.

Step 8: Updating the front-end AngularJS Application

I’ve updated the live front-end application to support using refresh tokens along with Resource Owner Password Credentials flow, so once you log in, and if you want to user refresh tokens you need to check the check box “Use Refresh Tokens” as the image below:

Login with Refresh Tokens

One you log in successfully, you will find new tab named “Refresh Tokens” on the top right corner, this tab will provide you with a view which allows you to obtain a new access token using the refresh token you obtained on log in, the view will look as the image below:

Refresh Token AngularJS

Lastly I’ve added new view named “/tokens” which is accessible only by username “Admin”. This view will list all available refresh tokens along with refresh token issue and expiry date. This view will allow the admin only to revoke a refresh tokens, the view will look as the below image:

List Refresh Tokens

I will write another post which shows how I’ve implemented this in the AngularJS application, for now you can check the code on my GitHub repo.

Conclusion

Security is really hard! You need to think about all the ins and outs, this post turned out to be too long and took way longer to compile and write than I expected, but hopefully it will be useful for anyone looking to implement refresh tokens. I would like to hear your feedback and comments if there is something missing or there is something we can enhance on this post.

You can check the demo application, play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

Follow me on Twitter @tjoudeh

References

  1. Special thanks goes to Dominick Baier for his detailed posts about OAuth, especially this post was very useful. As well I highly recommend checking  the Thinktecture.IdentityServer.
  2. Great post by Andrew Timney on persisting refresh tokens.

The post Enable OAuth Refresh Tokens in AngularJS App using ASP .NET Web API 2, and Owin appeared first on Bit of Technology.


ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app

$
0
0

Ok so it is time to enable ASP.NET Web API 2 external logins such as Facebook & Google then consume this in our AngularJS application. In this post we’ll add support to login using Facebook and Google+ external providers, then we’ll associate those authenticated social accounts with local accounts.

Once we complete the implementation in this post we’ll have an AngularJS application that uses OAuth bearer tokens to access any secured back-end API end point. This application will allow users to login using the resource owner password flow (Username/Password) along with refresh tokens, and support for using external login providers. So to follow along with this post I highly recommend to read previous parts:

You can check the demo application, play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

AngularJs External LoginsThere is a great walkthrough by Rick Anderson which shows how you can enable end users to login using social providers, the walkthrough uses VS 2013 MVC 5 template with individual accounts, to be honest it is quite easy and straight forward to implement this if you want to use this template, but in my case and if you’r following along with previous parts, you will notice that I’ve built the Web API from scratch and I added the needed middle-wares manually.

The MVC 5 template with individual accounts is quite complex, there are middle-wares for cookies, external cookies, bearer tokens… so it needs time to digest how this template work and maybe you do not need all this features in your API. There are two good posts about describing how external logins implemented in this template by Brock Allen and Dominick Baier.

So what I tried to do at the beginning is to add the features and middle-wares needed to support external logins to my back-end API (I need to use the minimal possible code to implement this), everything went good but the final step where I should receive something called external bearer token is not happening, I ended up with the same scenario in this SO question. It will be great if someone will be able to fork my repo and try to find a solution for this issue without adding Nuget packages for ASP.NET MVC and end up with all the binaries used in VS 2013 MVC 5 template.

I didn’t want to stop there, so I decided to do custom implementation for external providers with little help from the MVC 5 template, this implementation follows different flow other than the one in MVC 5 template; so I’m open for suggestions, enhancements, best practices on what we can add to the implementation I’ll describe below.

Sequence of events which will take place during external login:

  1. AngularJS application sends HTTP GET request to anonymous end point (/ExternalLogin) defined in our back-end API by specifying client_id, redirect_uri, response_type, the GET request will look as this:  http://ngauthenticationapi.azurewebsites.net/api/Account/ExternalLogin?provider=Google&response_type=token&client_id=ngAuthApp& redirect_uri=http://ngauthenticationweb.azurewebsites.net/authcomplete.html (more on redircet_uri value later on post)
  2. Once the end point receives the GET request, it will check if the user is authenticated, and let we assume he is not authenticated, so it will notify the middleware responsible for the requested external provider to take the responsibility for this call, in our case it is Google.
  3. The consent screen for Google will be shown, and the user will provide his Google credentials to authenticate.
  4. Google will callback our back-end API and Google will set an external cookie containing the outcome of the authentication from Google (contains all the claims from the external provider for the user).
  5. Google middleware will be listing for an event named “Authenticated” where we’ll have the chance to read all external claims set by Google. In our case we’ll be interested in reading the claim named “AccessToken” which represents a Google Access Token, where the issuer for this claim is not LOCAL AUTHORITY, so we can’t use this access token directly to authorize calls to our secure back-end API endpoints.
  6. Then we’ll set the external provider external access token as custom claim named “ExternalAccessToken” and Google middleware will redirect back the end point (/ExternalLogin).
  7. Now the user is authenticated using the external cookie so we need to check that the client_id and redirect_uri set in the initial request are valid and this client is configured to redirect for the specified URI (more on this later).
  8. Now the code checks if the external user_id along with the provider is already registered as local database account (with no password), in both cases the code will issue 302 redirect to the specified URI in the redirect_uri parameter, this URI will contain the following (“External Access Token”, “Has Local Account”, “Provider”, “External User Name”) as URL hash fragment not a query string.
  9. Once the AngularJS application receives the response, it will decide based on it if the user has local database account or not, based on this it will issue a request to one of the end points (/RegisterExternal or /ObtainLocalAccessToken). Both end points accept the external access token which will be used for verification and then using it to obtain local access token issued by LOCAL AUTHORITY. This local access token could be used to access our back-end API secured end points (more on external token verification and the two end points later in post).

Sounds complicated, right? Hopefully I’ll be able to simplify describing this in the steps below, so lets jump to the implementation:

Step 1: Add new methods to repository class

The methods I’ll add now will add support for creating the user without password as well finding and linking external social user account with local database account, they are self explanatory methods and there is nothing special about them, so open file “AuthRepository” and paste the code below:

public async Task<IdentityUser> FindAsync(UserLoginInfo loginInfo)
        {
            IdentityUser user = await _userManager.FindAsync(loginInfo);

            return user;
        }

        public async Task<IdentityResult> CreateAsync(IdentityUser user)
        {
            var result = await _userManager.CreateAsync(user);

            return result;
        }

        public async Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login)
        {
            var result = await _userManager.AddLoginAsync(userId, login);

            return result;
        }

 Step 2: Install the needed external social providers Nuget packages

In our case we need to add Google and Facebook external providers, so open Nuget package manger console and install the 2 packages below:

Install-Package Microsoft.Owin.Security.Facebook -Version 2.1.0
Install-Package Microsoft.Owin.Security.Google -Version 2.1.0

Step 3: Create Google and Facebook Application

I won’t go into details about this step, we need to create two applications one for Google and another for Facebook. I’ve followed exactly the steps used to create apps mentioned here so you can do this. We need to obtain AppId and Secret for both social providers and will use them later, below are the settings for my two apps:

AngularJS Facebook App AngularJS Google App

Step 4: Add the challenge result

Now add new folder named “Results” then add new class named “ChallengeResult” which derives from “IHttpActionResult” then paste the code below:

public class ChallengeResult : IHttpActionResult
    {        
        public string LoginProvider { get; set; }
        public HttpRequestMessage Request { get; set; }

        public ChallengeResult(string loginProvider, ApiController controller)
        {
            LoginProvider = loginProvider;
            Request = controller.Request;
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            Request.GetOwinContext().Authentication.Challenge(LoginProvider);

            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
            response.RequestMessage = Request;
            return Task.FromResult(response);
        }
    }

The code we’ve just implemented above will responsible to call the Challenge passing the name of the external provider we’re using (Google, Facebook, etc..), this challenge won’t fire unless our API sets the HTTP status code to 401 (Unauthorized),  once it is done the external provider middleware will communicate with the external provider system and the external provider system will display an authentication page for the end user (UI page by Facebook or Google where you’ll enter username/password for authentication).

Step 5: Add Google and Facebook authentication providers

Now we want to add two new authentication providers classes where we’ll be overriding the “Authenticated” method so we’ve the chance to read the external claims set by the external provider, those set of external claims will contain information about the authenticated user and we’re interested in the claim named “AccessToken”.

As I’mentioned earlier this token is for the external provider and issued by Google or Facebook, after we’ve received it we need to assign it to custom claim named “ExternalAccessToken” so it will be available in the request context for later use.

So add two new classes named “GoogleAuthProvider” and “FacebookAuthProvider”  to folder “Providers” and paste the code below to the corresponding class:

public class GoogleAuthProvider : IGoogleOAuth2AuthenticationProvider
    {
        public void ApplyRedirect(GoogleOAuth2ApplyRedirectContext context)
        {
            context.Response.Redirect(context.RedirectUri);
        }

        public Task Authenticated(GoogleOAuth2AuthenticatedContext context)
        {
            context.Identity.AddClaim(new Claim("ExternalAccessToken", context.AccessToken));
            return Task.FromResult<object>(null);
        }

        public Task ReturnEndpoint(GoogleOAuth2ReturnEndpointContext context)
        {
            return Task.FromResult<object>(null);
        }
    }

public class FacebookAuthProvider : FacebookAuthenticationProvider
    {
        public override Task Authenticated(FacebookAuthenticatedContext context)
        {
            context.Identity.AddClaim(new Claim("ExternalAccessToken", context.AccessToken));
            return Task.FromResult<object>(null);
        }
    }

Step 6: Add social providers middleware to Web API pipeline

Now we need to introduce some changes to “Startup” class, the changes as the below:

- Add three static properties as the code below:

public class Startup
    {
        public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
        public static GoogleOAuth2AuthenticationOptions googleAuthOptions { get; private set; }
        public static FacebookAuthenticationOptions facebookAuthOptions { get; private set; }

//More code here...
{

- Add support for using external cookies, this is important so external social providers will be able to set external claims, as well initialize the “OAuthBearerOptions” property as the code below:

public void ConfigureOAuth(IAppBuilder app)
        {
            //use a cookie to temporarily store information about a user logging in with a third party login provider
            app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
            OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

//More code here.....
}

- Lastly we need to wire up Google and Facebook social providers middleware to our Owin server pipeline and set the AppId/Secret for each provider, the values are removed so replace them with your app values obtained from step 3:

//Configure Google External Login
            googleAuthOptions = new GoogleOAuth2AuthenticationOptions()
            {
                ClientId = "xxx",
                ClientSecret = "xxx",
                Provider = new GoogleAuthProvider()
            };
            app.UseGoogleAuthentication(googleAuthOptions);

            //Configure Facebook External Login
            facebookAuthOptions = new FacebookAuthenticationOptions()
            {
                AppId = "xxx",
                AppSecret = "xxx",
                Provider = new FacebookAuthProvider()
            };
            app.UseFacebookAuthentication(facebookAuthOptions);

Step 7: Add “ExternalLogin” endpoint

As we stated earlier, this end point will accept the GET requests originated from our AngularJS app, so it will accept GET request on the form: http://ngauthenticationapi.azurewebsites.net/api/Account/ExternalLogin?provider=Google&response_type=token&client_id=ngAuthApp& redirect_uri=http://ngauthenticationweb.azurewebsites.net/authcomplete.html

So Open class “AccountController” and paste the code below:

private IAuthenticationManager Authentication
        {
            get { return Request.GetOwinContext().Authentication; }
        }        

// GET api/Account/ExternalLogin
        [OverrideAuthentication]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
        [AllowAnonymous]
        [Route("ExternalLogin", Name = "ExternalLogin")]
        public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
        {
            string redirectUri = string.Empty;

            if (error != null)
            {
                return BadRequest(Uri.EscapeDataString(error));
            }

            if (!User.Identity.IsAuthenticated)
            {
                return new ChallengeResult(provider, this);
            }

            var redirectUriValidationResult = ValidateClientAndRedirectUri(this.Request, ref redirectUri);

            if (!string.IsNullOrWhiteSpace(redirectUriValidationResult))
            {
                return BadRequest(redirectUriValidationResult);
            }

            ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);

            if (externalLogin == null)
            {
                return InternalServerError();
            }

            if (externalLogin.LoginProvider != provider)
            {
                Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
                return new ChallengeResult(provider, this);
            }

            IdentityUser user = await _repo.FindAsync(new UserLoginInfo(externalLogin.LoginProvider, externalLogin.ProviderKey));

            bool hasRegistered = user != null;

            redirectUri = string.Format("{0}#external_access_token={1}&provider={2}&haslocalaccount={3}&external_user_name={4}",
                                            redirectUri,
                                            externalLogin.ExternalAccessToken,
                                            externalLogin.LoginProvider,
                                            hasRegistered.ToString(),
                                            externalLogin.UserName);

            return Redirect(redirectUri);

        }

By looking at the code above there are lot of things happening so let’s describe what this end point is doing:

a) By looking at this method attributes you will notice that its configured to ignore bearer tokens, and it can be accessed if there is external cookie set by external authority (Facebook or Google) or can be accessed anonymously. it worth mentioning here that this end point will be called twice during the authentication, first call will be anonymously and the second time will be once the external cookie is set by the external provider.

b) Now the code flow will check if the user has been authenticated (External cookie has been set), if it is not the case then Challenge Result defined in step 4 will be called again.

c) Time to validate that client and redirect URI which is set by AngularJS application is valid and this client is configured to allow redirect for this URI, so we do not want to end allowing redirection to any URI set by a caller application which will open security threat (Visit this post to know more about clients and Allowed Origin). To do so we need to add a private helper function named “ValidateClientAndRedirectUri”, you can add this to the “AccountController” class as the code below:

private string ValidateClientAndRedirectUri(HttpRequestMessage request, ref string redirectUriOutput)
        {

            Uri redirectUri;

            var redirectUriString = GetQueryString(Request, "redirect_uri");

            if (string.IsNullOrWhiteSpace(redirectUriString))
            {
                return "redirect_uri is required";
            }

            bool validUri = Uri.TryCreate(redirectUriString, UriKind.Absolute, out redirectUri);

            if (!validUri)
            {
                return "redirect_uri is invalid";
            }

            var clientId = GetQueryString(Request, "client_id");

            if (string.IsNullOrWhiteSpace(clientId))
            {
                return "client_Id is required";
            }

            var client = _repo.FindClient(clientId);

            if (client == null)
            {
                return string.Format("Client_id '{0}' is not registered in the system.", clientId);
            }

            if (!string.Equals(client.AllowedOrigin, redirectUri.GetLeftPart(UriPartial.Authority), StringComparison.OrdinalIgnoreCase))
            {
                return string.Format("The given URL is not allowed by Client_id '{0}' configuration.", clientId);
            }

            redirectUriOutput = redirectUri.AbsoluteUri;

            return string.Empty;

        }

        private string GetQueryString(HttpRequestMessage request, string key)
        {
            var queryStrings = request.GetQueryNameValuePairs();

            if (queryStrings == null) return null;

            var match = queryStrings.FirstOrDefault(keyValue => string.Compare(keyValue.Key, key, true) == 0);

            if (string.IsNullOrEmpty(match.Value)) return null;

            return match.Value;
        }

d) After we validate the client and redirect URI we need to get the external login data along with the “ExternalAccessToken” which has been set by the external provider, so we need to add private class named “ExternalLoginData”, to do so add this class to the same “AccountController” class as the code below:

private class ExternalLoginData
        {
            public string LoginProvider { get; set; }
            public string ProviderKey { get; set; }
            public string UserName { get; set; }
            public string ExternalAccessToken { get; set; }

            public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
            {
                if (identity == null)
                {
                    return null;
                }

                Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);

                if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer) || String.IsNullOrEmpty(providerKeyClaim.Value))
                {
                    return null;
                }

                if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
                {
                    return null;
                }

                return new ExternalLoginData
                {
                    LoginProvider = providerKeyClaim.Issuer,
                    ProviderKey = providerKeyClaim.Value,
                    UserName = identity.FindFirstValue(ClaimTypes.Name),
                    ExternalAccessToken = identity.FindFirstValue("ExternalAccessToken"),
                };
            }
        }

e) Then we need to check if this social login (external user id with external provider) is already linked to local database account or this is first time to authenticate, based on this we are setting flag “hasRegistered” which will be returned to the AngularJS application.

f) Lastly we need to issue a 302 redirect to the “redirect_uri” set by the client application along with 4 values (“external_access_token”, “provider”, “hasLocalAccount”, “external_user_name”), those values will be added as URL hash fragment not as query string so they can be accessed by JS code only running on the return_uri page.

Now the AngularJS application has those values including external access token which can’t be used to access our secured back-end endpoints, to solve this issue we need to issue local access token with the help of this external access token. To do this we need to add two new end points where they will accept this external access token, validate it then generate local access token.

Why did we add two end points? Because if the external user is not linked to local database account; we need to issue HTTP POST request to the new endpoint “/RegisterExternal”, and if the external user already linked to local database account then we just need to obtain a local access token by issuing HTTP GET to endpoint “/ObtainLocalAccessToken”.

Before adding the two end points we need to add two helpers methods which they are used on these two endpoints.

Step 8: Verifying external access token

We’ve received the external access token from the external provider, and we returned it to the front-end AngularJS application, now we need to validate and make sure that this external access token which will be sent back from the front-end app to our back-end API is valid, and valid means (Correct access token, not expired, issued for the same client id configured in our back-end API). It is very important to check that external access token is issued to the same client id because you do not want our back-end API to end accepting valid external access tokens generated from different apps (client ids). You can read more about this here.

To do so we need to add class named “ExternalLoginModels” under folder “Models” and paste the code below:

namespace AngularJSAuthentication.API.Models
{
    public class ExternalLoginViewModel
    {
        public string Name { get; set; }

        public string Url { get; set; }

        public string State { get; set; }
    }

    public class RegisterExternalBindingModel
    {
        [Required]
        public string UserName { get; set; }

         [Required]
        public string Provider { get; set; }

         [Required]
         public string ExternalAccessToken { get; set; }

    }

    public class ParsedExternalAccessToken
    {
        public string user_id { get; set; }
        public string app_id { get; set; }
    }
}

Then we need to add private helper function named “VerifyExternalAccessToken” to class “AccountController”, the implantation for this function as the below:

private async Task<ParsedExternalAccessToken> VerifyExternalAccessToken(string provider, string accessToken)
        {
            ParsedExternalAccessToken parsedToken = null;

            var verifyTokenEndPoint = "";

            if (provider == "Facebook")
            {
                //You can get it from here: https://developers.facebook.com/tools/accesstoken/
                //More about debug_tokn here: http://stackoverflow.com/questions/16641083/how-does-one-get-the-app-access-token-for-debug-token-inspection-on-facebook

                var appToken = "xxxxx";
                verifyTokenEndPoint = string.Format("https://graph.facebook.com/debug_token?input_token={0}&access_token={1}", accessToken, appToken);
            }
            else if (provider == "Google")
            {
                verifyTokenEndPoint = string.Format("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={0}", accessToken);
            }
            else
            {
                return null;
            }

            var client = new HttpClient();
            var uri = new Uri(verifyTokenEndPoint);
            var response = await client.GetAsync(uri);

            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();

                dynamic jObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content);

                parsedToken = new ParsedExternalAccessToken();

                if (provider == "Facebook")
                {
                    parsedToken.user_id = jObj["data"]["user_id"];
                    parsedToken.app_id = jObj["data"]["app_id"];

                    if (!string.Equals(Startup.facebookAuthOptions.AppId, parsedToken.app_id, StringComparison.OrdinalIgnoreCase))
                    {
                        return null;
                    }
                }
                else if (provider == "Google")
                {
                    parsedToken.user_id = jObj["user_id"];
                    parsedToken.app_id = jObj["audience"];

                    if (!string.Equals(Startup.googleAuthOptions.ClientId, parsedToken.app_id, StringComparison.OrdinalIgnoreCase))
                    {
                        return null;
                    }

                }

            }

            return parsedToken;
        }

The code above is not the prettiest code I’ve written, it could be written in better way, but the essence of this helper method is to validate the external access token so for example if we take a look on Google case you will notice that we are issuing HTTP GET request to a defined endpoint by Google which is responsible to validate this access token, so if the token is valid we’ll read the app_id (client_id) and the user_id from the response, then we need to make sure that app_id returned as result from this request is exactly the same app_id used to configure Google app in our back-end API. If there is any differences then we’ll consider this external access token as invalid.

Note about Facebook: To validate Facebook external access token you need to obtain another single token for your application named appToken, you can get it from here.

Step 9: Generate local access token

Now we need to add another helper function which will be responsible to issue local access token which can be used to access our secure back-end API end points, the response for this token need to match the response we obtain when we call the end point “/token”, there is nothing special in this method, we are only setting the claims for the local identity then calling “OAuthBearerOptions.AccessTokenFormat.Protect” which will generate the local access token, so add  new private function named “” to “AccountController” class as the code below:

private JObject GenerateLocalAccessTokenResponse(string userName)
        {

            var tokenExpiration = TimeSpan.FromDays(1);

            ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);

            identity.AddClaim(new Claim(ClaimTypes.Name, userName));
            identity.AddClaim(new Claim("role", "user"));

            var props = new AuthenticationProperties()
            {
                IssuedUtc = DateTime.UtcNow,
                ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),
            };

            var ticket = new AuthenticationTicket(identity, props);

            var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);

            JObject tokenResponse = new JObject(
                                        new JProperty("userName", userName),
                                        new JProperty("access_token", accessToken),
                                        new JProperty("token_type", "bearer"),
                                        new JProperty("expires_in", tokenExpiration.TotalSeconds.ToString()),
                                        new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
                                        new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
        );

            return tokenResponse;
        }

Step 10: Add “RegisterExternal” endpoint to link social user with local account

After we added the helper methods needed it is time to add new API end point where it will be used to add the external user as local account and then link it with the created local account,  this method should be accessed anonymously because we do not have local access token yet; so add new method named “RegisterExternal” to class “AccountController” as the code below:

// POST api/Account/RegisterExternal
        [AllowAnonymous]
        [Route("RegisterExternal")]
        public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
        {

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var verifiedAccessToken = await VerifyExternalAccessToken(model.Provider, model.ExternalAccessToken);
            if (verifiedAccessToken == null)
            {
                return BadRequest("Invalid Provider or External Access Token");
            }

            IdentityUser user = await _repo.FindAsync(new UserLoginInfo(model.Provider, verifiedAccessToken.user_id));

            bool hasRegistered = user != null;

            if (hasRegistered)
            {
                return BadRequest("External user is already registered");
            }

            user = new IdentityUser() { UserName = model.UserName };

            IdentityResult result = await _repo.CreateAsync(user);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            var info = new ExternalLoginInfo()
            {
                DefaultUserName = model.UserName,
                Login = new UserLoginInfo(model.Provider, verifiedAccessToken.user_id)
            };

            result = await _repo.AddLoginAsync(user.Id, info.Login);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            //generate access token response
            var accessTokenResponse = GenerateLocalAccessTokenResponse(model.UserName);

            return Ok(accessTokenResponse);
        }

By looking at the code above you will notice that we need to issue HTTP POST request to the end point http://ngauthenticationapi.azurewebsites.net/api/account/RegisterExternal where the request body will contain JSON object of “userName”, “provider”, and “externalAccessToken” properties.

The code in this method is doing the following:

  • once we receive the request we’ll call the helper method  “VerifyExternalAccessToken” described earlier to ensure that this external access token is valid, and generated using our Facebook or Google application defined in our back-end API.
  • We need to check if the user_id obtained from the external access token and the provider combination has already registered in our system, if this is not the case we’ll add new user using the username passed in request body without a password to the table “AspNetUsers”
  • Then we need to link the local account created for this user to the provider and provider key (external user_id) and save this to table “AspNetUserLogins”
  • Lastly we’ll call the helper method named “GenerateLocalAccessTokenResponse” described earlier which is responsible to generate the local access token and return this in the response body, so front-end application can use this access token to access our secured back-end API endpoints.

The request body will look as the image below:

External Login Request

Step 11: Add “ObtainLocalAccessToken” for linked external accounts

Now this endpoint will be used to generate local access tokens for external users who already registered with local account and linked their external identities to a local account, this method is accessed anonymously and will accept 2 query strings (Provider, ExternalAccessToken). The end point can be accessed by issuing HTTP GET request to URI: http://ngauthenticationapi.azurewebsites.net/api/account/ObtainLocalAccessToken?provider=Facebook&externalaccesstoken=CAAKEF……….

So add new method named “ObtainLocalAccessToken” to controller “AccountController” and paste the code below:

[AllowAnonymous]
        [HttpGet]
        [Route("ObtainLocalAccessToken")]
        public async Task<IHttpActionResult> ObtainLocalAccessToken(string provider, string externalAccessToken)
        {

            if (string.IsNullOrWhiteSpace(provider) || string.IsNullOrWhiteSpace(externalAccessToken))
            {
                return BadRequest("Provider or external access token is not sent");
            }

            var verifiedAccessToken = await VerifyExternalAccessToken(provider, externalAccessToken);
            if (verifiedAccessToken == null)
            {
                return BadRequest("Invalid Provider or External Access Token");
            }

            IdentityUser user = await _repo.FindAsync(new UserLoginInfo(provider, verifiedAccessToken.user_id));

            bool hasRegistered = user != null;

            if (!hasRegistered)
            {
                return BadRequest("External user is not registered");
            }

            //generate access token response
            var accessTokenResponse = GenerateLocalAccessTokenResponse(user.UserName);

            return Ok(accessTokenResponse);

        }

By looking at the code above you will notice that we’re doing the following:

  • Make sure that Provider and ExternalAccessToken query strings are sent with the HTTP GET request.
  • Verifying the external access token as we did in the previous step.
  • Check if the user_id and provider combination is already linked in our system.
  • Generate a local access token and return this in the response body so front-end application can use this access token to access our secured back-end API endpoints.

Step 12:Updating the front-end AngularJS application

I’ve updated the live front-end application to support using  social logins as the image below:

AngularJS Social Login

Now once the user clicks on one of the social login buttons, a popup window will open targeting the URI: http://ngauthenticationapi.azurewebsites.net/api/Account/ExternalLogin?provider=Google&response_type=token&client_id=ngAuthApp &redirect_uri=http://ngauthenticationweb.azurewebsites.net/authcomplete.html and the steps described earlier in this post will take place.

What worth mentioning here that the “authcomplete.html” page is an empty page which has JS function responsible to read the URL hash fragments and pass them to AngularJS controller in callback function, based on the value of the fragment (hasLocalAccount) the AngularJS controller will decide to call end point “/ObtainLocalAccessToken” or display a view named “associate” where it will give the end user the chance to set preferred username only and then call the endpoint “/RegisterExternal”.

The “associate” view will look as the image below:

AngularJS Social Login Associate

That is it for now folks! Hopefully this implementation will be useful to integrate social logins with your ASP.NET Web API and keep the API isolated from any front end application, I believe by using this way we can integrate native iOS or Android Apps that using Facebook SDKs easily with our back-end API, usually the Facebook SDK will return Facebook access token and we can then obtain local access token as we described earlier.

If you have any feedback, comment, or better way to implement this; then please drop me comment, thanks for reading!

You can check the demo application, play with the back-end API for learning purposes (http://ngauthenticationapi.azurewebsites.net), and check the source code on Github.

Follow me on Twitter @tjoudeh

References

  1. Informative post by Brock Allen about External logins with OWIN middleware.
  2. Solid post by Dominick Baier on Web API Individual Accounts.
  3. Great post by Rick Anderson on VS 2013 MVC 5 template with individual accounts.
  4. Helpful post by Valerio Gheri on How to login with Facebook access token.

The post ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app appeared first on Bit of Technology.

ASP.NET Web API Documentation using Swagger

$
0
0

Recently I was working on designing and implementing a large scale RESTful API using ASP.NET Web API, this RESTful API contains large number of endpoints with different data models used in the request/response payloads.

Proper documentation and having a solid API explorer (Playground) is a crucial thing for your API success and likability by developers. There is a very informative slides by John Musser which highlights the top 10 reasons which makes developers hate your API, and unsurprisingly the top one is the lack of documentation and the absence of interactive documentation; so to avoid this pitfall I decided to document my Web API using Swagger.

Swagger basically is a framework for describing, consuming, and visualizing RESTful APIs. The nice thing about Swagger that it is really keeps the documentation system, the client, and the server code in sync always, in other words the documentation of methods, parameters, and models are tightly integrated into the server code.

ASP.NET Web API Documentation using Swagger

So in this short post I decided to add documentation using Swagger for a simple ASP.NET Web API project which contains a single controller with different HTTP methods, the live demo API explorer can be accessed here, and the source code can be found on GitHub. The final result for the API explorer will look as the image below:

Asp.Net Web Api Swagger

Swagger is language-agnostic so there are different implementations for different platforms. For the ASP.NET Web API world there is a solid open source implementation named “Swashbuckle”  this implementation simplifies adding Swagger to any Web API project by following simple steps which I’ll highlight in this post.

The nice thing about Swashbuckle that it has no dependency on ASP.NET MVC, so there is no need to include any MVC Nuget packages in order to enable API documentation, as well Swashbuckle contains an embedded version of swagger-ui which will automatically serve up once Swashbuckle is installed.

Swagger-ui basically is a dependency-free collection of HTML, Javascript, and CSS files that dynamically generate documentation and sandbox from a Swagger-compliant API, it is a Single Page Application which forms the play ground shown in the image above.

Steps to Add Swashbuckle to ASP.NET Web API

The sample ASP.NET Web API project I want to document is built using Owin middleware and hosted on IIS, I’ll not go into details on how I built the Web API, but I’ll focus on how I added Swashbuckle to the API.

For brevity the API contains single controller named “StudentsController”, the source code for the controller can be viewed here, as well it contains a simple “Student” Model class which can be viewed here.

Step 1: Install the needed Nuget Package

Open NuGet Package Manager Console and install the below package:

Install-Package Swashbuckle

Once this package is installed it will install a bootstrapper (App_Start/SwaggerConfig.cs) file which initiates Swashbuckle on application start-up using WebActivatorEx.

Step 2: Call the bootstrapper in “Startup” class

Now we need to add the highlighted line below to “Startup” class, so open the Startup class and replace it with the code below:

[assembly: OwinStartup(typeof(WebApiSwagger.Startup))]
namespace WebApiSwagger
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
           
            HttpConfiguration config = new HttpConfiguration();
            
            WebApiConfig.Register(config);

            Swashbuckle.Bootstrapper.Init(config);

            app.UseWebApi(config);

        }
    }
}

Step 3: Enable generating XML documentation

This is not required step to use “Swashbuckle” but I believe it is very useful for API consumers especially if you have complex data models, so to enable XML documentation, right click on your Web API project — >”Properties” then choose “Build” tab, after you choose it scroll down to the “Output” section and check “XML documentation file” check box and set the file path to: “bin\[YourProjectName].XML” as the image below. This will add an XML file to the bin folder which contains all the XML comments you added as annotation to the controllers or data models.

Swagger XML Comments

Step 4: Configure Swashbuckle to use XML Comments

By default Swashbuckle doesn’t include the annotated XML comments on the API controllers and data models into the generated specification and the UI, to include them we need to configure it, so open file “SwaggerConfig.cs” and paste the highlighted code below:

public class SwaggerConfig
    {
        public static void Register()
        {
            Swashbuckle.Bootstrapper.Init(GlobalConfiguration.Configuration);

            // NOTE: If you want to customize the generated swagger or UI, use SwaggerSpecConfig and/or SwaggerUiConfig here ...

            SwaggerSpecConfig.Customize(c =>
            {
                c.IncludeXmlComments(GetXmlCommentsPath());
            });
        }

        protected static string GetXmlCommentsPath()
        {
            return System.String.Format(@"{0}\bin\WebApiSwagger.XML", System.AppDomain.CurrentDomain.BaseDirectory);
        }
    }

Step 5: Start annotating your API methods and data models

Now we can start adding XML comments to API methods so for example if we take a look on the HTTP POST method in Students Controller as the code below:

/// <summary>
        /// Add new student
        /// </summary>
        /// <param name="student">Student Model</param>
        /// <remarks>Insert new student</remarks>
        /// <response code="400">Bad request</response>
        /// <response code="500">Internal Server Error</response>
        [Route("")]
        [ResponseType(typeof(Student))]
        public IHttpActionResult Post(Student student)
        {
            //Method implementation goes here....
        }

You will notice that each XML tag  is reflected on the Swagger properties as the image below:
Swagger XML Tags Mapping

Summary

You can add Swashbuckle seamlessly to any Web API project, and then you can easily customize the generated specification along with the UI (swagger-ui). You can check the documentation and troubleshooting section here.

That’s it for now, hopefully this post will be useful for anyone looking to document their ASP.NET Web API, if you have any question or you have used another tool for documentation please drop me a comment.

The live demo API explorer can be accessed here, and the source code can be found on GitHub.

Follow me on Twitter @tjoudeh

The post ASP.NET Web API Documentation using Swagger appeared first on Bit of Technology.

Secure ASP.NET Web API 2 using Azure Active Directory, Owin Middleware, and ADAL

$
0
0

Recently I’ve been asked by many blog readers on how to secure ASP.NET Web API 2 using Azure Active Directory, in other words we want to outsource the authentication part from the Web API to Microsoft Azure Active Directory (AD). We have already seen how the authentication can be done with local database accounts, and social identity providers, so in this tutorial we’ll try something different and we’ll obtain the bearer access tokens from external authority which is our Azure Active Directory (AD).

Microsoft Azure Active Directory (AD) is PaaS service available to every Azure subscription, this service is used to store information about users and organizational structure. We’ll use this service as our Authority service which will be responsible to secure our Resource (Web API) and issue access tokens and refresh tokens using OAuth 2 Code flow grant.

The resource (Web API) should be consumed by a Client, so the client will be requesting the data from the resource (Web API), but in order for this request to be accepted by the resource, the client must send a valid access token obtained from the Authority service (Azure AD) with each request. Do not worry if this is not clear now, I’ll describe this thoroughly while we’re implementing this tutorial.

Azure Active Directory Web Api

What we’ll build in this tutorial?

As you noticed in the previous posts, I’m not big fan of the built in templates in Visual Studio 2013, those templates mix MVC controllers along with Web API controllers and bring confusion to the developers, so in this post I’ve decided to build simple ASP.NET Web API secured by Azure AD using Owin middle-ware components which we’ll add manually using Nuget, then I’ll build simple client (desktop forms application) which will consume this Web API.

The Source code for this tutorial is available on GitHub.

Building the Back-end Resource (Web API)

Step 1: Creating the Web API Project

In this tutorial I’m using Visual Studio 2013 and .Net framework 4.5, to get started create an empty solution and name it “WebApiAzureActiveDirectory”, then add new empty ASP.NET Web application named “WebApiAzureAD.Api”, the selected template for the project will be “Empty” template with no core dependencies, check the image below:

Web Api Azure AD Project

Step 2: Install the needed NuGet Packages

This project is empty so we need to install the NuGet packages needed to setup our Owin server and configure ASP.NET Web API 2 to be hosted within an Owin server, so open NuGet Package Manager Console and install the below packages:

Install-Package Microsoft.AspNet.WebApi
Install-Package Microsoft.AspNet.WebApi.Owin
Install-Package Microsoft.Owin.Host.SystemWeb
Install-Package Microsoft.Owin.Security.ActiveDirectory

The use for the first three packages have been discussed on this post, the package “Install-Package Microsoft.Owin.Security.ActiveDirectory” is responsible to configure our Owin middle-ware server to use Microsoft Azure Active Directory to offload the authentication process to it. We’ll see how we’ll do this in the coming steps.

Step 3: Register the Web API into Azure Active Directory

Now we need to jump to Azure Management Portal in order to register our Web API (Resource) as an application in our Azure Active Directory (Authority) so this authority will accept issuing tokens for our Web API, to do so and after your successful login to Azure Management Portal,  click on “Active Directory” in the left hand navigation menu, choose your active directory tenant you want to register your Web API with, then select the “Applications” tab, then click on the add icon at bottom of the page. Once the modal window shows as the image below select “Add an application my organization is developing”.

Add App to Azure AD

Then a wizard of 2 steps will show up asking you to select the type of the app you want to add, in our case we are currently adding a Web API so select “Web Application and/or Web API”, then provide a name for the application, in my case I’ll call it “WebApiAzureAD”, then click next.

Add WebApi To Azure Active Directory

In the second step as the image below we need to fill two things, the Sign-On URL which is usually will be your base Url for your Web API, so in my case it will be “http://localhost:55577″, and the second field APP ID URI will usually be filled with a URI that Azure AD can use for this app, it usually take the form of “http://<your_AD_tenant_name>/<your_app_friendly_name>” so we will replace this with the correct values for my app and will be filed as “http://taiseerjoudeharamex.onmicrosoft.com/WebApiAzureAD” then click OK.

Important Note:

  • On production environment, all the communication should be done over HTTPS only, the access token we’ll transmit from the client to the API should be transmitted over HTTPS only.
  • To get your AD tenant name, you can navigate to to your active directory and click on the “Domains” tab.

Add Web Api To Azure Active Directory

Step 4: Expose our Web API to other applications

After our Web API has been added to Azure Active Directory apps, we need to do one more thing here which is exposing our permission scopes to client apps developers who will build clients to consume our Web API. To do so we need to change our Web API configuring using the application manifest. Basically the application manifest is a JSON file that represents our application identity configuration.

So as the image below and after you navigate to the app we’ve just added click on “Manage Manifest” icon at the bottom of the page, then click on “Download Manifest”.

Download Manifest

Open the downloaded JSON application manifest file and replace the “appPermissions” node with the below JSON snippet. This snippet is just an example of how to expose a permission scope known as user impersonation, do not forget to generate new GUID for the “permessionid” value. You can read more about Web API configuration here.

"appPermissions": [
    {
      "claimValue": "user_impersonation",
      "description": "Allow the application full access to the service on behalf of the signed-in user",
      "directAccessGrantTypes": [],
      "displayName": "Have full access to the service",
      "impersonationAccessGrantTypes": [
        {
          "impersonated": "User",
          "impersonator": "Application"
        }
      ],
      "isDisabled": false,
      "origin": "Application",
      "permissionId": "856aba87-e34d-4857-9cb1-cc4ac92a35f8",
      "resourceScopeType": "Personal",
      "userConsentDescription": "Allow the application full access to the service on your behalf",
      "userConsentDisplayName": "Have full access to the service"
    }
  ]

After you replaced the “appPermission” node, save the application manifest file locally then upload it again to your app using the “Upload Manifest” feature, now we have added our Web API as an application to the Azure Active Directory, so lets go back to visual studio and do the concrete implementation for the Web API.

Step 5: Add Owin “Startup” Class

Now back to our visual studio, we need to build the API components because we didn’t use a ready made template, this way is cleaner and you understand the need and use for each component you install in your solution, so add new class named “Startup”. It will contain the code below:

using Microsoft.Owin;
using Microsoft.Owin.Security.ActiveDirectory;
using Owin;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Http;

[assembly: OwinStartup(typeof(WebApiAzureAD.Api.Startup))]
namespace WebApiAzureAD.Api
{

    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();
 
            ConfigureAuth(app);

            WebApiConfig.Register(config);

            app.UseWebApi(config);
        }

        private void ConfigureAuth(IAppBuilder app)
        {
            app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                {
                    Audience = ConfigurationManager.AppSettings["Audience"],
                    Tenant = ConfigurationManager.AppSettings["Tenant"]
                });
        }
    }

}

What we’ve done here is simple, and you can check my other posts to understand what the need for “Startup” class and how it works.

What worth explaining here is what the private method “ConfigureAuth” responsible for, so the implementation inside this method basically telling our Web API that the authentication middle ware which will be used is going to be “Windows Azure Active Directory Bearer Tokens” for the specified Active Directory “Tenant” and “Audience” (APP ID URI). Now any Api Controller added to this Web Api and decorated with [Authorize] attribute will only understand bearer tokens issued from this specified Active Directory Tenant and Application, any other form of tokens will be rejected and HTTP status code 401 will be returned.

It is a good practice to store the values for your Audience, Tenant, Secrets, etc… in a configuration file and not to hard-code them, so open the web.config file and add 2 new “appSettings” as the snippet below:

<appSettings>
    <add key="Tenant" value="taiseerjoudeharamex.onmicrosoft.com" />
    <add key="Audience" value="http://taiseerjoudeharamex.onmicrosoft.com/WebApiAzureAD" />
  </appSettings>

Before moving to the next step, do not forget to add the class “WebApiConfig.cs” under folder “App_Start” which contains the code below:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }

Step 6: Add a Secure OrdersController

Now we want to add a secure controller to serve our Orders. What I mean by a “secure” controller that its a controller attribute with [Authorize] attribute and can be accessed only when the request contains a valid access token issued by our Azure AD tenant for this app only. To keep things simple we’ll return static data. So add new controller named “OrdersController” and paste the code below:

[Authorize]
    [RoutePrefix("api/orders")]
    public class OrdersController : ApiController
    {
        [Route("")]
        public IHttpActionResult Get()
        {
           var isAuth = User.Identity.IsAuthenticated;
           var userName = User.Identity.Name;

           return Ok(Order.CreateOrders());

        }
    }

    #region Helpers

    public class Order
    {
        public int OrderID { get; set; }
        public string CustomerName { get; set; }
        public string ShipperCity { get; set; }
        public Boolean IsShipped { get; set; }


        public static List<Order> CreateOrders()
        {
            List<Order> OrderList = new List<Order> 
            {
                new Order {OrderID = 10248, CustomerName = "Taiseer Joudeh", ShipperCity = "Amman", IsShipped = true },
                new Order {OrderID = 10249, CustomerName = "Ahmad Hasan", ShipperCity = "Dubai", IsShipped = false},
                new Order {OrderID = 10250,CustomerName = "Tamer Yaser", ShipperCity = "Jeddah", IsShipped = false },
                new Order {OrderID = 10251,CustomerName = "Lina Majed", ShipperCity = "Abu Dhabi", IsShipped = false},
                new Order {OrderID = 10252,CustomerName = "Yasmeen Rami", ShipperCity = "Kuwait", IsShipped = true}
            };

            return OrderList;
        }
    }

    #endregion

Till this step we’ve built our API and configured the authentication part to be outsourced to Azure Active Directory (AD), now it is the time to build a client which will be responsible to consume this back-end API and talk to our Azure AD tenant to obtain access tokens.

Building the Client Application

As I stated before, we’ll build very simple desktop application to consume the back-end API, but before digging into the code, let’s add this application to our Azure AD tenant and configure the permission for the client to allow accessing the back-end API.

Step 7: Register the Client Application into Azure Active Directory

To do so navigate to Azure Management Portal again and add new application as we did on step 3. But this time and for this application will select “Native Client Application”, give the application friendly name, in my case I’ll name it “ClientAppAzureAD” and for the redirect URI I’ll enter “http://WebApiAzureADClient”. You can think for this URI as the endpoint which will be used to return the authorization code from Azure AD which will be used later to exchange this authorization code with an access token. No need to worry your self about this, because all of this will be handled for us auto-magically when we use and talk about Azure Active Directory Authentication Library (ADAL) toolkit.

Add Client To Azure AD

Step 8: Configure the Client Application Permissions

This step is very important, we need to configure the client app and specify which registered application it can access, in our case we need to give the client application permission to access our back-end API (WebApiAzureAD), the delegated permissions selected will be “Have full access to the service”, and if you notice this permission list is coming from the modified “appPermission” node in the JSON application manifest file we’ve modified in step 4. After you do this click Save.

Grant Permession

Step 9: Adding the client application project

Time to get back to visual studio to build the client application, You can use any type of client application you prefer (console app, WPF, windows forms app, etc..) in my case I’ll use windows form application, so I’ll add to our solution a new project of type “Windows Forms Application” named “WebApiAzureAD.Client”.

Once the project is added to the solution, we need to add some new keys to the “app.config” file which we’ll use to communicate with our Azure AD tenant, so open app.config file and paste the the snippet below:

<appSettings>
   
    <add key="ida:AADInstance" value="https://login.windows.net/{0}" />
    <add key="ida:Tenant" value="taiseerjoudeharamex.onmicrosoft.com" />
    <add key="ida:ClientId" value="1c92b0cc-6d13-497d-87da-bef413c9f26f" />
    <add key="ida:RedirectUri" value="http://WebApiAzureADClient" />
    
    <add key="ApiResourceId" value="http://taiseerjoudeharamex.onmicrosoft.com/WebApiAzureAD" />
    <add key="ApiBaseAddress" value="http://localhost:55577/" />
    
  </appSettings>

So the value for “ClientId” key is coming from the “Client Id” value for the client we defined in Azure AD, and the same applies for the key “RedirectUri”.

For the value for “ApiResourceId” and “ApiBaseAddress” both values are coming from the back-end API application we already registered with Azure AD.

Step 10: Install the needed Nuget Packages for the client application

We need to install the below Nuget packages in order to be able to call the back-end API and our Azure AD tenant to obtain tokens, so open package manager console and install the below:

PM> Install-Package Microsoft.Net.Http
PM> Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory

The first package installed is responsible to HttpClient for sending requests over HTTP, as well as HttpRequestMessage and HttpResponseMessage for processing HTTP messages.

The second package installed  represents Azure AD Authentication Library (ADAL) which is used to enable a .NET client application to authenticate users against Azure AD and obtain access tokens to call back-end Web API.

Step 11: Obtain the token and call the back-end API

Now it is the time to implement the logic in the client application which is responsible to obtain the access token from our Azure AD tenant, then use this access token to access the secured API end point.

To do so, add new button on the form and open “Form1.cs” and paste the code below:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
        private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        Uri redirectUri = new Uri(ConfigurationManager.AppSettings["ida:RedirectUri"]);

        private static string authority = String.Format(aadInstance, tenant);

        private static string apiResourceId = ConfigurationManager.AppSettings["ApiResourceId"];
        private static string apiBaseAddress = ConfigurationManager.AppSettings["ApiBaseAddress"];

        private AuthenticationContext authContext = null;

        private async void button1_Click(object sender, EventArgs e)
        {

            authContext = new AuthenticationContext(authority);

            AuthenticationResult authResult = authContext.AcquireToken(apiResourceId, clientId, redirectUri);

            HttpClient client = new HttpClient();

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);

            HttpResponseMessage response = await client.GetAsync(apiBaseAddress + "api/orders");
          
            string responseString = await response.Content.ReadAsStringAsync();
           
            MessageBox.Show(responseString);

        }
    }

What we’ve implemented now is the below:

  • We’ve read bunch of settings which will be used to inform the client application what is the Uri/name for Azure AD tenant that it should call, the client id we obtained after registering the client application in Azure AD. As well we need to read the App Id Uri (ApiResourceId) which tells the client which Web API it should call to get the data from.
  • We’ve created an instance of the “AuthenticationContext” class, this instance will represent the authority that our client will work with. In our case the authority will be our Azure AD tenant represented by the Uri https://login.windows.net/taiseerjoudeharamex.onmicrosoft.com.
  • Now we’ll call the method “AcquireToken” which will be responsible to do internally the heavy lifting for us and the communication with our authority to obtain an access token. To do so and as we are building client application we need to pass three parameters which they are: a. The resource which the token will be sent to, b. The client id. c. The redirect uri for this client.
  • Now you will ask your self where the end user using this system will enter his AD credentials? The nice thing here that the AuthenticationContext class which is part of ADAL will take care of showing the authentication dialog in a popup and do the right communication with the correct end point where the end user will be able to provide his AD credentials, there is no need to write any extra single line of code to do this, thanks for the nice abstraction provided by ADAL. We’ll see this in action once we test the application.
  • After the user provides his valid AD credentials, a token is obtained and returned as property in the “AuthenticationResult” response along with other properties.
  • Now we need to do an ordinary HTTP GET method to our secure end point (/api/orders) and we’ve to pass this obtained access token in the authorization header using a bearer scheme. If everything goes correctly we’ll receive HTTP status code 200 along with the secured orders data.

Step 12: Testing the solution

We are ready to test the application, jump to your solution, right click on Web Api project “WebApiAzureAD.Api” select “Debug” then “Start New Instance”, then jump to your desktop application and do the same, start new instance of the EXE, click on the button and you will see the ADAL authentication dialog popups as the image blow.

ADAL Auth Window

Fill the credentials for an AD user registered in our tenant and click sign in, if the credentials provided is correct you will receive an access token as the image below, this access token will be sent int the authorization header for the GET request and you will receive your orders data.

Azure AD Access Token

Now if you tried to click on the button again without terminating the EXE (client app) you will notice that the ADAL authorization popup will not show up again and you get the token directly without providing any credentials, thanks to the built-in token cache which keeps track of the tokens.

If you closed the application and reopen it, then the ADAL authorization pop up will show up again, maybe this is not so convenience for end users. So to over come this issue you can use strategy called “token caching” which allows you to persist the obtained tokens and store them securely on a local protected file using DPAPI protection, this is better way to do it because you will not hit the authority server if you closed your client application and you still have a valid access token when you open the client again. You can read more about this implementation here.

Conclusion

Securing your ASP.NET Web API 2 by depending on Azure AD is something easy, if you are building an API for the enterprise which will be used by different applications, you can easily get up and running in no time.

As well the ADAL toolkit is providing us with great level of abstraction over the OAuth 2.0 specifications which makes developers life easy when building the clients, they will focus on business logic and the authentication/autherization part is will be handled by ADAL.

That’s it for now, I hope this tutorial will help you securing your ASP.NET Web API 2 using Azure AD, if you have any question or you have suggestions please drop me a comment.

The Source code for this tutorial is available on GitHub.

Follow me on Twitter @tjoudeh

Resources

The post Secure ASP.NET Web API 2 using Azure Active Directory, Owin Middleware, and ADAL appeared first on Bit of Technology.

Decouple OWIN Authorization Server from Resource Server

$
0
0

Recently I’ve received lot of comments and emails asking how we can decouple the OWIN Authorization Server we’ve built in the previous posts from the resources we are protecting. If you are following the posts mentioned below you will notice that we’ve only one software component (API) which plays both roles: Authorization Server and Resource Server.

There is nothing wrong with the the current implementation because OAuth 2.0 specifications never forces the separation between the Authorization Server and the Resource Server, but in many cases and especially if you have huge resources and huge number of endpoints you want to secure; then it is better from architecture stand point to decouple the servers. So you will end up having a stand alone Authorization Server, and another stand alone Resource Server which contains all protected resources, as well this Resource Server will understand only the access tokens issued from the Authorization Server.

You can check the source code on Github.

OAuth 2.0 Roles: Authorization Server, Resource Server, Client, and Resource Owner

Before we jump into implementation and how we can decouple the servers I would like to emphasis on OAuth 2.0 roles defined in the specifications; so we’ll have better understanding of the responsibility of each role, by looking at the image below you will notice that there are 4 roles involved:

OAuth 2.0 Roles

Resource Owner:

The entity or person (user) that owns the protected Resource.

Resource Server:

The server which hosts the protected resources, this server should be able to accept the access tokens issued by the Authorization Server and respond with the protected resource if the the access token is valid.

Client Applications:

The application or the (software) requesting access to the protected resources on the Resource Server, this client (on some OAuth flows) can request access token on behalf of the Resource Owner.

Authorization Server:

The server which is responsible for managing authorizations and issuing access tokens to the clients after validating the Resource Owner identity.

Note: In our architecture we can have single Authorization Server which is responsible to issue access token which can be consumed by multiple Resource Servers.

Decoupling OAuth 2.0 OWIN Authorization Server from Resource Server

In the previous posts we’ve built the Authorization Server and the Resource Server using a single software component (API), this API can be accessed on (http://ngauthenticationAPI.azurewebsites.net), in this demo I will guide you on how to create new standalone Resource API and host it on different machine other than the Authorization Server machine, then configure the Resource API to accept only access tokens issued from our Authorization Server. This new Resource Server is hosted on Azure can be accessed on (http://ngauthenticationResourcesAPI.azurewebsites.net).

Note: As you noticed from the previous posts we’ve built a protected resource (OrdersController) which can be accessed by issuing HTTP GET to the end point(http://ngauthenticationAPI.azurewebsites.net/api/orders), this end point is considered as a resource and should be moved to the Resource Server we’ll build now, but for the sake of keeping all the posts on this series functioning correctly; I’ll keep this end point in our Authorization Server, so please consider the API we’ve built previously as our standalone Authorization Server even it has a protected resource in it.

Steps to build the Resource Server

In the steps below, we’ll build another Web API which will contain our protected resources, for the sake of keeping it simple, I’ll add only one secured end point named “ProtectedController”, any authorized request to this end point should contain valid bearer token issued from our Authorization Server, so let’s start implementing this:

Step 1: Creating the Resource Web API Project

We need to add new ASP.NET Web application named “AngularJSAuthentication.ResourceServer” to our existing solution named “AngularJSAuthentication”, the selected template for the new project will be “Empty” template with no core dependencies, check the image below:

Resourse Server New Project

Step 2: Install the needed NuGet Packages

This project is empty so we need to install the NuGet packages needed to setup our OWIN Resource Server, configure ASP.NET Web API to be hosted within an OWIN server, and configure it to only uses OAuth 2.0 bearer tokens as authorization middle ware; so open NuGet Package Manager Console and install the below packages:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0

The usage for each package has been covered on the previews posts, feel free to check this post to know the rational of using each package is used for.

Step 3: Add OWIN “Startup” Class

Now we want to add new class named “Startup”. It will contain the code below:

[assembly: OwinStartup(typeof(AngularJSAuthentication.ResourceServer.Startup))]
namespace AngularJSAuthentication.ResourceServer
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            ConfigureOAuth(app);

            WebApiConfig.Register(config);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
            
        }

        private void ConfigureOAuth(IAppBuilder app)
        {
            //Token Consumption
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
            {
            });
        }
    }
}

As we’ve covered in previous posts, this class will be fired once our Resource Server starts, as you noticed I’ve enabled CORS so this resource server can accept XHR requests coming from any origin.

What worth noting here is the implementation for method “ConfigureOAuth”, inside this method we are configuring the Resource Server to accept (consume only) tokens with bearer scheme, if you forget this one; then your Resource Server won’t understand the bearer tokens sent to it.

Step 3: Add “WebApiConfig” Class

As usual we need to add the WebApiConfig class under folder “App_Start” which contains the code below:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }

This class is responsible to enable routing attributes on our controller.

Step 4: Add new protected (secured) controller

Now we want to add a controller which will serve as our protected resource, this controller will return list of claims for the authorized user, those claims for sure are encoded within the access token we’ve obtained from the Authorization Server. So add new controller named “ProtectedController” under “Controllers” folder and paste the code below:

[Authorize]
    [RoutePrefix("api/protected")]
    public class ProtectedController : ApiController
    {
        [Route("")]
        public IEnumerable<object> Get()
        {
            var identity = User.Identity as ClaimsIdentity;
           
            return identity.Claims.Select(c => new
            {
                Type = c.Type,
                Value = c.Value
            });
        }
    }

Notice how we attribute the controller with [Authorize] attribute which will protect this resource and only will allow HTTP GET requests containing a valid bearer access token sent in the authorization header to pass, in more details when the request is received the OAuth bearer authentication middle ware will perform the following:

  1. Extracting the access token which is sent in the “Authorization header” with the “Bearer” scheme.
  2. Extracting the authentication ticket from access token, this ticket will contain claims identity and any additional authentication properties.
  3. Checking the validity period of the authentication ticket.

Step 5: Hosting the Authorization Server and Resource Server on different machines

Until this step and if you are developing locally on your dev machine, if you tried to obtain an access token from your Authorization Server i.e. (http://AuthServer/token) and then send this access token to the secured end point in our Resource Server i.e. (http://ResServer/api/protected) the result for this request will pass and you will have access to the protected resource, how is this happening?

One your dev machine once you request an access token from your Authorization Server; the OAuth middleware will use the default data protection provider in your Authorization Server, so it will use the “validationKey” value in machineKey node stored in machine.config file to issue the access token and protect it. The same case applies when you send the access token to your Resource Server, it will use the same machineKey to decrypt the access token and extract the authentication ticket from it.

The same applies if you are planing on your production environment to host your Authorization Server and your Resource Server on the same machine.

But in our case I’m hosting my Authorization Server on Azure website using West-US region, and my Resource Server is hosted on Azure websites on East-US region so both are totally on different machines and they share different machine.config files. For sure I can’t change anything on machine.config file because it is used by different sites on the Azure VMs I’m hosting my APIs on it.

So to solve this case we need to override the machineKey node for both APIs (Authorization Server and Resource Server) and share the same machineKey between both web.config files.

To do so we need to generate a new machineKey using this online tool, the result after using the tool will be as the below: As advised by Barry Dorrans it is not recommend to use an online tool to generate your machineKey because you do not know if this online tool will store the value for your machineKey in some secret database, it is better to generate the machineKey by your self.

To do so I’ll follow the steps mentioned in article KB 2915218, Appendix A which uses Power Shell commands to generate machineKey, so after you open Power Shell and run the right command as the image below you will receive new machineKey
PowerShell MachineKey

<machineKey validationKey="A970D0E3C36AA17C43C5DB225C778B3392BAED4D7089C6AAF76E3D4243E64FD797BD17611868E85D2E4E1C8B6F1FB684B0C8DBA0C39E20284B7FCA73E0927B20" decryptionKey="88274072DD5AC1FB6CED8281B34CDC6E79DD7223243A527D46C09CF6CA58DB68" validation="SHA1" decryption="AES" />

Note: Do not use those for production and generate a new machineKey for your Servers using Power Shell.

After you generate it open the web.config file for both the Authorization Server (AngularJSAuthentication.API project) and for the Resource Server (AngularJSAuthentication.ResourceServer) and paste the machineKey node inside the <system.web> node as the below:

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <machineKey validationKey="VALUE GOES HERE" 
                decryptionKey="VALUE GOES HERE" 
                validation="SHA1" 
                decryption="AES"/>
  </system.web>

By doing this we’ve unified the machineKey for both Authorization Server and Resource Server (Only this API in case of Azure shared hosting or any other shared host) and we are ready now to test our implementation.

Step 6: Testing the Authorization Server and Resource Server

Now we need to obtain an access token from our Authorization Server as we did before in the previous posts, so we can issue HTTP POST to the end point (http://ngauthenticationapi.azurewebsites.net/token) including the resource owner username and password as the image below:

Obtain Access Token

If the request succeeded we’ll receive an access token, then we’ll use this access token to send HTTP GET request to our new Resource Server using the protected end point (http://ngauthenticationresourcesapi.azurewebsites.net/api/protected), for sure we need to send the access token in the Authorization header using bearer scheme, the request will be as the image below:

Consume Access Token

As you notice we’re now able to access the protected resource in our new Resource Server and the claims for this identity which obtained from the Authorization Server are extracted.

That’s it for now folks, hopefully this short walk through helped in understanding how we can decouple the Authorization Server from the Resource Server.

If you have any comment or question please drop me a comment

You can use the following link to check the demo application.

You can use the following link to test the Authorization Server (http://ngauthenticationAPI.azurewebsites.net),

You can use the following link to test the Resource Server (http://ngauthenticationResourcesAPI.azurewebsites.net) 

You can check the source code on Github.

Follow me on Twitter @tjoudeh

References

The post Decouple OWIN Authorization Server from Resource Server appeared first on Bit of Technology.

Two Factor Authentication in ASP.NET Web API & AngularJS using Google Authenticator

$
0
0

Last week I was looking on how to enable Two Factor Authentication in a RESTful ASP.NET Web API service using Soft Tokens not SMS. Most of the examples out there show how to implement this in MVC application where there will be some cookies transmitted between requests, this approach defeats the stateless nature of the RESTful APIs, as well most of the examples ask for the passcode on the login form only, so there was no complete example on how to implement TFA in RESTful API.

The live AngularJS demo application is hosted on Azure, the source code for this tutorial on GitHub.

Basically the requirements I needed to fulfill in the solution I’m working on are the following:

  • The Web API should stay stateless, no cookies should be transmitted between the consumer and the API.
  • Each call to the Web API should be authenticated using OAuth 2.0 Bearer tokens as we implemented before.
  • Two Factor Authentication is required only for some sensitive API requests, in other words for some selective sensitive endpoints (i.e. transfer money) should ask for Two Factor Authentication time sensitive passcode along with the valid bearer access token, and the other endpoints will use only One Factor for authentication which is the OAuth 2.0 bearer access tokens only.
  • We need to build cost effective solution, no need to add new cost by sending SMSs which contain a passcode,  we will depend on our users’ smartphones as a Soft Token. The user needs to install Google Authenticator application on his/her smartphone which will generate a time sensitive passcode valid for only 30 seconds.
  • Lastly the front-end application which will consume this API will be built using AngularJS and should support displaying QR codes for the Preshared key.

TFA Featured Image

Before jumping into the implementation I’d like to emphasize some concepts to make sure that we understand the core components of Two Factor Authentication and how Google Authenticator works as Soft Token.

What is Two Factor Authentication?

Any user trying to access a system can be authenticated by one of the below ways:

  1. Something the user knows (Password, Secret).
  2. Something the user owns (Mobile Phone, Device).
  3. Something the user is (Bio-metric, fingerprint).

Two Factor authentication is a combination of any two of the above three ways. When want to apply this to real business world applications, we usually use the first and the second ways. This is because the third way (Biometrics) is very expensive and complicated to roll out, and the end user experience can be problematic.

So Two Factor authentication is made up of something that the user knows and another thing the user owns. The smartphone is something the user owns so receiving a passcode (receiving SMS or call) on it, or generating a passcode using the smartphone (as in our case) will allow us to add Two Factor authentication.

In our Back-end API we’ll ask the user to provide the below two separate factors when he/she wants to access a sensitive endpoint, the factors the user should provide are:

  1. The OAuth 2.0 bearer access tokens which is granted to the user when he provides his/her username and password at an earlier stage.
  2. The time sensitive passcode generated on the user smartphone which he/she owns using Google Authenticator.

What is Google Authenticator?

Google Authenticator is a mobile based application which is available on different platforms, the application works as a soft token which is responsible for generating time sensitive passcodes which will be used to implement Two Factor authentication for Google services. Basically the time sensitive passcode generated contains six digits which is valid for 30 seconds only, then new six digits will be generated directly.

Once you install the Google Authenticator application on your smartphone, it will basically ask you to enter Preshared Secret/Key between you and the application, this Preshared Key will be generated from our back-end API for each user register in our system and will be displayed on the UI as QR code or as plain text so the user can add this Preshared Key to Google Authenticator. More about generating this Preshared Key later in this post.

The nice thing about Google Authenticator is that it generates the time sensitive passcode on the smartphone without depending on anything, there is no need for internet connection or access to Google services to generate this passcode. How is this happening? Well the Google Authenticator implements Time-based One-time Password Algorithm (TOTP) which is an algorithm that computes a one-time password from a shared secret key and the current time, TOTP is based on HMAC-based One Time Password algorithm (HOTP) with a time-stamp replacing the incrementing counter in HOTP. You can check the implementation for Google Authenticator here.

Google Authenticator

In our solution the first step to authenticate the user is by providing his username and password in order to obtain an OAuth 2.0 bearer access token which is considered a type of knowledge-factor authentication, then as we agreed before and for certain selective sensitive API end-points (require second factor authentication), the user will open Google Authenticator application installed on his/her smartphone, lookup the time sensitive passcode which is generated from the Preshared key, and this passcode represents something the user owns (represents ownership-factor authentication).

Process flow for using Google Authenticaor with our Back-end API

In this section I’ll show you the process flow which the user will follow in our Two Factor authentication enabled solution in order to allow the user to access the selective sensitive API end-points.

  • The user will register in our-back end system by providing username,password and confirm password (normal registration process), upon successful registration and in the back-end API,  a Preshared Key (PSK) is generated for this user and returned to the UI in form of QR code and plain text (5FDAEHNBNM6W3L2S) so the user will open Google Authenticator application installed on his smartphone and scan this Preshared Key or enter it manually and select Time Based key. UI will look as the image below:

TFA Signup Form

  • Now the user will login to our system by providing his username/password and obtaining an OAuth 2.0 access token which will allow him to access our protected API resources, as long as he is trying to access non elevated sensitive end-point (i.e. transfer money) then our back-end API will be happy with only the one-factor authentication (knowledge-based factor) which is the OAuth 2.0 bearer access token only. As on the images blow the user is allowed to access his transactions history (non sensitive end point, yet it is protected by one-factor authentication).

Login

Transactions History

  • Now the user wants to perform an elevated sensitive request (Transfer Money), this end-point in out back-end API is configured to ask for second ownership factor to authenticate before completing the request, so the UI will ask the user to enter the time sensitive pass-code provided by Google Authenticator, the UI for Transfer Money will look as below:

Transfer Money TFA Code

  • The user will fill the form with the details he wants, if he tried to issue a transfer request without providing the second factor authentication (pass code) the request will be rejected and HTTP 401 unauthorized will be returned because this endpoint is sensitive and needs a second ownership factor to authenticate successfully. So the user will grab his smartphone, open Google Authenticator application and type the six digits pass code appears that on the application and hit transfer button. This six digits code will be sent in a custom HTTP header along with the OAuth 2.0 access token to this sensitive end-point.

Google Authenticator Passcode

  • Now the API receives this pass code for example (472307), and checks the code validity, if it is valid then the API will process the request and the user will complete transferring the money successfully (execution for the sensitive end-point is successful).

Money Transfer Successfully

The last step is the trickiest one, you are not asking yourself how this six digits code generated by Google Authenticator which will keep changing every 30 seconds will be understood and considered authentic by our back-end API. To answer this we need to take a brief look on how Google Authenticator produces those six digits; because we’ll simulate the same procedure at our back-end API.

How does Google Authenticator work?

As we have stated before Google Authenticator supports both TOTP algorithm on top of HOTP algorithm for generating onetime pass-codes or time sensitive pass-codes.

The idea behind HOTP is that the server (our back-end API) and client (Google Authenticator app) share a Preshared Key value and a counter, The preshared key and the counter are used to compute a one-time passcode independently on both sides (Notice it is a one-time passcode not a time sensitive passcode). Whenever a passcode is generated and used, the counter is incremented on both sides, allowing the server and client to remain in sync.

TOTP is built on top of HOTP, it uses HOTP same algorithm with one clear difference; the counter used in TOTP is replaced by the current time. But the challenge here is that this six digits passcode will keep changing rapidly with every second change and this will not be feasible because the end user will not be able to enter this number when asked for.

To solve this issue we’ll generate the number (counter) corresponding to 00 second of the current minute and let it remain constant for the next 30 seconds; by doing this the six digits passcode will become usable and will stay constant for the next 30 seconds. Note that all time calculations are based on UTC, so there is no need to worry about the time zone for the server and the time zone for the user using Google Authenticator application.

When the sensitive API endpoint receives this time sensitive passcode, it will repeat the process described above. Basically the API will know the user id from the OAuth access token sent, then fetch the Preshared key saved in the database for this user, and from there it will generate the time sensitive passcode and compare it with the passcode sent from the client application (UI), if the passcode sent form the UI matches the one generated in the back-end API then the API will consider this passcode authentic and process the request successfully.

Note: One of the greatest books which describes how Google Authenticator works is Pro ASP.NET Web API Security (Chapter 14) written by Badrinarayanan Lakshmiraghavan. Highly recommend if you are interested in ASP.NET Web API security in general.

Now it is time to start implementing this solution, this is the longest theory I’ve written so far in all my blog posts so we’d better to move to the code :)

Building the Back-End API

I highly recommend to read my previous post Token Based Authentication before implementing the steps below and enabling Two Factor Authentication, because the steps mentioned below are very identical to the previous post, so I’ll list the identical steps and will be very brief in explaining what each step is doing except for the new steps which are related to enabling Two Factor Authentication in our back-end API.

Step 1: Creating the Web API Project

Create an empty solution and name it “TFAWebApiAngularJS” then add a new ASP.NET Web application named “TwoFactorAuthentication.API”, the selected template for the project will be “Empty” template with no core dependencies. Notice that the authentication is set to “No Authentication” taking into consideration that we’ll add this manually.

Step 2: Installing the needed NuGet Packages:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0
Install-Package Microsoft.AspNet.Identity.Owin -Version 2.0.1
Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.0.1

Step 3: Add Owin “Startup” Class

Right click on your project then add a new class named “Startup”. It will contain the code below:

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            ConfigureOAuth(app);

            WebApiConfig.Register(config);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);

        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            OAuthBearerAuthenticationOptions OAuthBearerOptions = new OAuthBearerAuthenticationOptions();

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                //For Dev enviroment only (on production should be AllowInsecureHttp = false)
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new SimpleAuthorizationServerProvider()
            };

            // Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);

            //Token Consumption
            app.UseOAuthBearerAuthentication(OAuthBearerOptions);

        }
    }

Basically this class will configure our back-end API to use OAuth 2.0 bearer tokens to secure the endpoints attribute with [Authorize] attribute, as well it also set the access token to expire after 24 hours. We’ll implement the class “SimpleAuthorizationServerProvider” in later steps.

Step 4: Add “WebApiConfig” class

Right click on your project, add a new folder named “App_Start”, inside this class add a class named “WebApiConfig”, then paste the code below:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }

Step 5: Add the ASP.NET Identity System

Now we’ll configure our user store to use ASP.NET Identity system to store the user profiles, to do this we need a database context class which will be responsible for communicating with our database, so add a new class and name it “AuthContext” then paste the code snippet below:

public class AuthContext : IdentityDbContext<ApplicationUser>
    {
        public AuthContext()
            : base("AuthContext")
        {
        }
    }

    public class ApplicationUser : IdentityUser
    {
        [Required]
        [MaxLength(16)]
        public string PSK { get; set; }
    }

As you see in the code above, the “AuthContext” class is inheriting from “IdentityDbContext<ApplicationUser>”, where the “ApplicationUser” inherits from “IdentityUser”, this is done like this because we need to extend the “AspNetUsers” table and add a new column named “PSK” which will contain the Preshared key generated for this user in our back-end API. More on generating this Preshared key later in the post.

Now we want to add “UserModel” which contains the properties needed to be sent once we register a user, this model is a POCO class with some data annotations attributes used for the sake of validating the registration payload request. So add a new folder named “Models” then add a new class named “UserModel” and paste the code below:

public class UserModel
    {
        [Required]
        [Display(Name = "User name")]
        public string UserName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

Now we need to add a new connection string named “AuthContext” in our Web.Config file, so open you web.config and add the below section:

<connectionStrings>
    <add name="AuthContext" connectionString="Data Source=.\sqlexpress;Initial Catalog=TFAAuth;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
  </connectionStrings>

Step 6: Add Repository class to support ASP.NET Identity System

Now we want to implement two methods needed in our application which they are: “RegisterUser” and “FindUser”, so adda  new class named “AuthRepository” and paste the code snippet below:

public class AuthRepository :IDisposable    
    {
        private AuthContext _ctx;

        private UserManager<ApplicationUser> _userManager;

        public AuthRepository()
        {
            _ctx = new AuthContext();
            _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_ctx));
        }

        public async Task<IdentityResult> RegisterUser(UserModel userModel)
        {
            ApplicationUser user = new ApplicationUser
            {
                UserName = userModel.UserName,
                TwoFactorEnabled = true,
                PSK = OneTimePass.GenerateSharedPrivateKey()
            };

            var result = await _userManager.CreateAsync(user, userModel.Password);

            return result;
        }

        public async Task<ApplicationUser> FindUser(string userName, string password)
        {
            ApplicationUser user = await _userManager.FindAsync(userName, password);
            
            return user;
        }

        public void Dispose()
        {
            _ctx.Dispose();
            _userManager.Dispose();

        }
    }

By looking at the code above you will notice that we are generating Preshared key for the registered user by calling the static method “OneTimePass.GeneratePresharedKey”, this Preshared key will be sent back to the end user so he will enter this 16 characters key in his Google Authenticator application.

Step 7: Add support for generating Preshared keys and passcodes

Note: There are lot of implementations for Google Authenticator algorithms (HOTP, and TOTP) out there in different platforms including .NET, but there is nothing that beats Badrinarayanan Lakshmiraghavan’s implementation in simplicity and minimal number of code used. The implementation exists and is available for public in the companion source code which comes with his Pro ASP.NET Web API Security book, so all the credit for the below implementation goes for Badrinarayanan, and I’ll not re-explain how the implementation is done. Badrinarayanan explained it in a very simple way, so my recommendation is to check his book.

So add a new folder named “Services” and inside it add a new file named “TimeSensitivePassCode.cs” then paste the code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Web;
using System.Text;

namespace TwoFactorAuthentication.API.Services
{
    public static class TimeSensitivePassCode
    {
        public static string GeneratePresharedKey()
        {
            byte[] key = new byte[10]; // 80 bits
            using (var rngProvider = new RNGCryptoServiceProvider())
            {
                rngProvider.GetBytes(key);
            }

            return key.ToBase32String();
        }

        public static IList<string> GetListOfOTPs(string base32EncodedSecret)
        {
            DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);

            long counter = (long)Math.Floor((DateTime.UtcNow - epochStart).TotalSeconds / 30);
            var otps = new List<string>();

            otps.Add(GetHotp(base32EncodedSecret, counter - 1)); // previous OTP
            otps.Add(GetHotp(base32EncodedSecret, counter)); // current OTP
            otps.Add(GetHotp(base32EncodedSecret, counter + 1)); // next OTP

            return otps;
        }

        private static string GetHotp(string base32EncodedSecret, long counter)
        {
            byte[] message = BitConverter.GetBytes(counter).Reverse().ToArray(); //Intel machine (little endian) 
            byte[] secret = base32EncodedSecret.ToByteArray();

            HMACSHA1 hmac = new HMACSHA1(secret, true);

            byte[] hash = hmac.ComputeHash(message);
            int offset = hash[hash.Length - 1] & 0xf;
            int truncatedHash = ((hash[offset] & 0x7f) << 24) |
            ((hash[offset + 1] & 0xff) << 16) |
            ((hash[offset + 2] & 0xff) << 8) |
            (hash[offset + 3] & 0xff);

            int hotp = truncatedHash % 1000000; 
            return hotp.ToString().PadLeft(6, '0');
        }
    }

    public static class StringHelper
    {
        private static string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

        public static string ToBase32String(this byte[] secret)
        {
            var bits = secret.Select(b => Convert.ToString(b, 2).PadLeft(8, '0')).Aggregate((a, b) => a + b);

            return Enumerable.Range(0, bits.Length / 5).Select(i => alphabet.Substring(Convert.ToInt32(bits.Substring(i * 5, 5), 2), 1)).Aggregate((a, b) => a + b);
        }

        public static byte[] ToByteArray(this string secret)
        {
            var bits = secret.ToUpper().ToCharArray().Select(c => Convert.ToString(alphabet.IndexOf(c), 2).PadLeft(5, '0')).Aggregate((a, b) => a + b);

            return Enumerable.Range(0, bits.Length / 8).Select(i => Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
        }

    }
}

Briefly what we’ve implemented in this class is the below

  • We’ve added a static method named “GeneratePresharedKey” which is responsible for generating 16 characters as our Preshared key, basically it is an array of 80 bit which is encoded using base32 format, this base32 format uses 26 letters A-Z and six digits 2-7 which will produce restricted set of characters that can be conveniently used by end users.
  • Why did we encod the key using base32 format? Because Google Authenticator uses the same encoding to help end users who prefer to enter the Preshared key manually without any confusion, the numbers which might confuse the users with letters are omitted (i.e 0,1,8,9). The implementation for Base32 encoding can be found on the extension method named “ToBase32String” in the helper class “StringHelper”.
  • We’ve implemented the static method “GetHotp” which accepts the base32 encoded Preshared key (16 characters) and a counter, this method will be responsible for generating the One time passcodes.
  • As we stated before the implementation of TOTP is built on top of HOTP, the only major difference is that the counter is replaced by time, so in the method “GetListOfOTPs” we are getting three time sensitive pass codes, one in the past, another in the present, and one in the future; the reason for doing this is to accommodate for the clock alter/shift between the server time and the clock on the smartphone where the passcode is generated using Google Authenticator, we are basically making it easy for the end user when he enters the time sensitive passcodes.

Step 8: Add our “Account” Controller

Now we’ll add a Web API controller which will be used to register a new users, so under add new folder named “Controllers” then add an Empty Web API 2 Controller named “AccountController” and paste the code below:

[RoutePrefix("api/Account")]
    public class AccountController : ApiController
    {
        private AuthRepository _repo = null;

        public AccountController()
        {
            _repo = new AuthRepository();
        }

        // POST api/Account/Register
        [AllowAnonymous]
        [Route("Register")]
        public async Task<IHttpActionResult> Register(UserModel userModel)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result = await _repo.RegisterUser(userModel);
            
            IHttpActionResult errorResult = GetErrorResult(result);

            if (errorResult != null)
            {
                return errorResult;
            }

            ApplicationUser user = await _repo.FindUser(userModel.UserName, userModel.Password);

            return Ok(new { PSK = user.PSK });
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _repo.Dispose();
            }

            base.Dispose(disposing);
        }

        private IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (!result.Succeeded)
            {
                if (result.Errors != null)
                {
                    foreach (string error in result.Errors)
                    {
                        ModelState.AddModelError("", error);
                    }
                }

                if (ModelState.IsValid)
                {
                    // No ModelState errors are available to send, so just return an empty BadRequest.
                    return BadRequest();
                }

                return BadRequest(ModelState);
            }

            return null;
        }
    }

It is worth noting here that inside method “Register” we’re returning the SPK after registering the user successfully, this PSK will be displayed on the UI on form of QR code and plain text so we give the user 2 options to enter it in Google Authenticator.

Step 9: Add Protected Money Transactions Controller with Two Actions

Now we’ll add a protected controller which can be accessed only if the request contains valid OAuth 2.0 bearer access token, inside this controller we’ll add 2 action methods, one of those action methods “GetHistory” will only requires One-Factor authentication (only bearer tokens) to process the request, on the other hand there will be another sensitive action method named “PostTransfer” which will require Two Factor authentication to process the request.

So add new Web API controller named “TransactionsController” under folder Controllers and paste the code below:

[Authorize]
    [RoutePrefix("api/Transactions")]
    public class TransactionsController : ApiController
    {
        [Route("history")]
        public IHttpActionResult GetHistory()
        {
            return Ok(Transaction.CreateTransactions());
        }

        [Route("transfer")]
        [TwoFactorAuthorize]
        public IHttpActionResult PostTransfer(TransferModeyModel transferModeyModel)
        {
            return Ok();
        }
    }

    #region Helpers

    public class Transaction
    {
        public int ID { get; set; }
        public string CustomerName { get; set; }
        public string Amount { get; set; }
        public DateTime ActionDate { get; set; }


        public static List<Transaction> CreateTransactions()
        {
            List<Transaction> TransactionList = new List<Transaction> 
            {
                new Transaction {ID = 10248, CustomerName = "Taiseer Joudeh", Amount = "$1,545.00", ActionDate = DateTime.UtcNow.AddDays(-5) },
                new Transaction {ID = 10249, CustomerName = "Ahmad Hasan", Amount = "$2,200.00", ActionDate = DateTime.UtcNow.AddDays(-6)},
                new Transaction {ID = 10250,CustomerName = "Tamer Yaser", Amount = "$300.00", ActionDate = DateTime.UtcNow.AddDays(-7) },
                new Transaction {ID = 10251,CustomerName = "Lina Majed", Amount = "$3,100.00", ActionDate = DateTime.UtcNow.AddDays(-8)},
                new Transaction {ID = 10252,CustomerName = "Yasmeen Rami", Amount = "$1,100.00", ActionDate = DateTime.UtcNow.AddDays(-9)}
            };

            return TransactionList;
        }
    }

    public class TransferModeyModel
    {
        public string FromEmail { get; set; }
        public string ToEmail { get; set; }
        public double Amount { get; set; }
    }

    #endregion
}

Notice that the “Authorize” attribute is set on the controller level for both actions, which means that both actions need the bearer token to process the request, but on the action method “PostTransfer” you will notice that there is new custom authorize filter attribute named “TwoFactorAuthorizeAttribute” setting on top of this action method, this custom authorize attribute is responsible for enabling Two Factor authentication on any sensitive controller, action method, or HTTP verb in future. All we need to do is just use this custom attribute as an attribute on the endpoint we want to elevate the security level on and require a second factor authentication to process the request.

Step 10: Implement the “TwoFactorAuthorizeAttribute”

Before starting to implement the “TwoFactorAuthorizeAttribute” we need to add simple helper class which will be responsible to inspect request headers looking for the time sensitive passcode sent by the client application in a custom header, so to implement this add a new folder named “Helpers” and inside it add a new file named “OtpHelper” and paste the code below:

public static class OtpHelper
    {
        private const string OTP_HEADER = "X-OTP";

        public static bool HasValidTotp(this HttpRequestMessage request, string key)
        {
            if (request.Headers.Contains(OTP_HEADER))
            {
                string otp = request.Headers.GetValues(OTP_HEADER).First();
                
                // We need to check the passcode against the past, current, and future passcodes
               
                if (!string.IsNullOrWhiteSpace(otp))
                {
                    if (TimeSensitivePassCode.GetListOfOTPs(key).Any(t => t.Equals(otp)))
                    {
                        return true;
                    }
                }

            }
            return false;
        }
    }

So basically this class is looking for a custom header named “X-OTP” in the HTTP request headers, if this header was found we’ll send the value of it (time sensitive passcode) along with Preshared key for this authenticated user to the method “GetListOfOTPs” which we defined in step 7.

If this time sensitive passcode exists in the list of pass codes (past, current, and future passcodes) then this means that this passcode is valid and authentic, otherwise the passcode is invalid or the user didn’t include it in the request.

Now to implement the custom “TwoFactorAuthorizeAttribute” we need to add a new folder named “Filters” and inside it add a new class named “TwoFactorAuthorizeAttribute” then paste the code below:

public class TwoFactorAuthorizeAttribute : AuthorizationFilterAttribute
    {
        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {
            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;

            var preSharedKey = principal.FindFirst("PSK").Value;
            bool hasValidTotp = OtpHelper.HasValidTotp(actionContext.Request, preSharedKey);

            if (hasValidTotp)
            {
                return Task.FromResult<object>(null);
            }
            else
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, new CustomError() { Code = 100, Message = "One Time Password is Invalid" });
                return Task.FromResult<object>(null);
            }
        }
    }

    public class CustomError
    {
        public int Code { get; set; }
        public string Message { get; set; }
    }

What we’ve implemented in this customer authorization filer is the following:

  • This custom Authorize attribute inherits from “AuthorizationFilterAttribute” and we are overriding the “OnAuthorizationAsync” method.
  • We can be 100% sure that the code execution flow will not reach this authorization filter attribute if the user is not authenticated by the OAuth 2.0 bearer token sent, this custom authorize attribute run later in the pipeline after the “Authorize” attribute.
  • Inside the “OnAuthorizationAsync” method we are looking for the claims for the authenticated user, this claim will contain custom claim of type “PSK” which contains the value of the Preshared key for this authenticated user (Didn’t implement this yet, you will see how we set the claim in the next step).
  • Then we will call the helper method named “OtpHelper.HasValidTotp” by passing the HTTP request which contains the time sensitive pass code in a custom header along with the Preshared key. If this method returns true then we will consider this request a valid one and that has fulfilled the Two Factor authentication requirements.
  • If the request doesn’t contain the valid time sensitive passcode then we will return HTTP status code 401 along with a message and an arbitrary integer code used in the UI.

 Step 11: Implement the “SimpleAuthorizationServerProvider” class

Add a new folder named “Providers” then add new class named “SimpleAuthorizationServerProvider”, paste the code snippet below:

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
            return Task.FromResult<object>(null);
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var  allowedOrigin = "*";
            ApplicationUser appUser = null;

            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

            using (AuthRepository _repo = new AuthRepository())
            {
                 appUser = await _repo.FindUser(context.UserName, context.Password);

                if (appUser == 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.Name, context.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Role, "User"));
            identity.AddClaim(new Claim("PSK", appUser.PSK));

            var props = new AuthenticationProperties(new Dictionary<string, string>
                {
                    { 
                        "userName", context.UserName
                    }
                });

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

        public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {

            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }

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

It is worth mentioning here that in the second method “GrantResourceOwnerCredentials” which is responsible for validating the username and password sent to the authorization server token endpoint, and after fetching the user from the database, we are adding a custom claim named “PSK”, the value for this claim contains the Preshared key for this authenticated user. This claim will be included in the signed OAuth 2.0 bearer token, that’s why we can directly get the PSK value in step 10.

 Step 12: Testing the Back-end API

First step to test the API is to register a new user so open your favorite REST client application in order to issue an HTTP request to register the user, so issue an HTTP POST request to the endpoint https://ngtfaapi.azurewebsites.net/api/account/register as the image below:

Register User

If the request processed successfully you will receive 200 status along with the Preshared Key, so open Google Authenticator app and enter this key manually.

Now we need to obtain OAuth 2.0 bearer access token to allow us to request the protected end points, this represent the first factor authentication because the user will provide his username and password, so we need to issue HTTP POST request to the endpoint http://ngtfaapi.azurewebsites.net/token as the image below:

Request Access Token

Now after we have a valid OAuth 2.0 access token, we need to try to send an HTTP POST request to the protected elevated security endpoint which requires second factor authentication, we’ll issue the request to the endpoint https://ngtfaapi.azurewebsites.net/api/transactions/transfer asshown in the image below, but we’ll not set the value for the custom header (X-OTP) so definitely the API will response with 401 unauthorized access

Failed TFA Request

Now in order to make this request authentic we need to open Google Authenticator and get the passcode from there and send it in the (X-OTP) custom header, so the authentic request will be as shown in the image below:

Authentic TFA Request

The live AngularJS demo application is hosted on Azure, the source code for this tutorial on GitHub.

That’s it for now folks!

I hope this step by step post will help you enable Two Factor Authentication into ASP.NET Web API RESTful services for selective sensitive endpoints, if you have any question please drop me a comment.

Follow me on Twitter @tjoudeh

References

The post Two Factor Authentication in ASP.NET Web API & AngularJS using Google Authenticator appeared first on Bit of Technology.

JSON Web Token in ASP.NET Web API 2 using Owin

$
0
0

In the previous post Decouple OWIN Authorization Server from Resource Server we saw how we can separate the Authorization Server and the Resource Server by unifying the “decryptionKey” and “validationKey” key values in machineKey node in the web.config file for the Authorization and the Resource server. So once the user request an access token from the Authorization server, the Authorization server will use this unified key to encrypt the access token, and at the other end when the token is sent to the Resource server, it will use the same key to decrypt this access token and extract the authentication ticket from it.

The source code for this tutorial is available on GitHub.

This way works well if you have control on your Resource servers (Audience) which will rely on your Authorization server (Token Issuer) to obtain access tokens from, in other words you are fully trusting those Resource servers so you are sharing with them the same “decryptionKey” and “validationKey” values.

But in some situations you might have big number of Resource servers rely on your Authorization server, so sharing the same “decryptionKey” and “validationKey” keys with all those parties become inefficient process as well insecure, you are using the same keys for multiple Resource servers, so if a key is compromised all the other Resource servers will be affected.

To overcome this issue we need to configure the Authorization server to issue access tokens using JSON Web Tokens format (JWT) instead of the default access token format, as well on the Resource server side we need to configure it to consume this new JWT access tokens, as well you will see through out this post that there is no need to unify the “decryptionKey” and “validationKey” key values anymore if we used JWT.

Featured Image

What is JSON Web Token (JWT)?

JSON Web Token is a security token which acts as a container for claims about the user, it can be transmitted easily between the Authorization server (Token Issuer), and the Resource server (Audience), the claims in JWT are encoded using JSON which make it easier to use especially in applications built using JavaScript.

JSON Web Tokens can be signed following the JSON Web Signature (JWS) specifications, as well it can be encrypted following the JSON Web Encryption (JWE) specifications, in our case we will not transmit any sensitive data in the JWT payload, so we’ll only sign this JWT to protect it from tampering during the transmission between parties.

JSON Web Token (JWT) Format

Basically the JWT is a string which consists of three parts separated by a dot (.) The JWT parts are: <header>.<payload>.<signature>.

The header part is JSON object which contains 2 nodes always and looks as the following: 

{ "typ": "JWT", "alg": "HS256" }
 The “type” node has always “JWT” value, and the node “alg” contains the algorithm used to sign the token, in our case we’ll use “HMAC-SHA256″ for signing.

The payload part is JSON object as well which contains all the claims inside this token, check the example shown in the snippet below:

{
  "unique_name": "SysAdmin",
  "sub": "SysAdmin",
  "role": [
    "Manager",
    "Supervisor"
  ],
  "iss": "http://myAuthZServer",
  "aud": "379ee8430c2d421380a713458c23ef74",
  "exp": 1414283602,
  "nbf": 1414281802
}

All those claims are not mandatory  in order to build JWT, you can read more about JWT claims here. In our case we’ll always use those set of claims in the JWT we are going to issue, those claims represent the below:

  • The “sub” (subject) and “unique_claim” claims represent the user name this token issued for.
  • The “role” claim represents the roles for the user.
  • The “iss” (issuer) claim represents the Authorization server (Token Issuer) party.
  • The “aud” (audience) claim represents the recipients that the JWT is intended for (Relying Party – Resource Server). More on this unique string later in this post.
  • The “exp” (expiration time) claim represents the expiration time of the JWT, this claim contains UNIX time value.
  • The “nbf” (not before) claim represent the time which this JWT must not be used before, this claim contains UNIX time vale.

Lastly the signature part of the JWT is created by taking the header and payload parts, base 64 URL encode them, then concatenate them with “.”, then use the “alg” defined in the <header> part to generate the signature, in our case “HMAC-SHA256″. The resulting part of this signing process is byte array which should be base 64 URL encoded then concatenated with the <header>.<payload> to produce a complete JWT.

JSON Web Tokens support in ASP.NET Web API and Owin middleware.

There is no direct support for issuing JWT in ASP.NET Web API or ready made Owin middleware responsible for doing this, so in order to start issuing JWTs we need to implement this manually by implementing the interface “ISecureDataFormat” and implement the method “Protect”. More in this later. But for consuming the JWT in a Resource server there is ready middleware named “Microsoft.Owin.Security.Jwt” which understands validates, and and de-serialize JWT tokens with minimal number of line of codes.

So most of the heavy lifting we’ll do now will be in implementing the Authorization Server.

What we’ll build in this tutorial?

We’ll build a single Authorization server which issues JWT using ASP.NET Web API 2 on top of Owin middleware, the Authorization server is hosted on Azure (http://JwtAuthZSrv.azurewebsites.net) so you can test it out by adding new Resource servers. Then we’ll build a single Resource server (audience) which will process JWTs issued by our Authorization server only.

I’ll split this post into two sections, the first section will be for creating the Authorization server, and the second section will cover creating Resource server.

The source code for this tutorial is available on GitHub.

Section 1: Building the Authorization Server (Token Issuer)

Step 1.1: Create the Authorization Server Web API Project

Create an empty solution and name it “JsonWebTokensWebApi” then add a new ASP.NET Web application named “AuthorizationServer.Api”, the selected template for the project will be “Empty” template with no core dependencies. Notice that the authentication is set to “No Authentication”.

Step 1.2: Install the needed NuGet Packages:

Open package manger console and install the below Nuget packages:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0
Install-Package System.IdentityModel.Tokens.Jwt -Version 4.0.0
Install-Package Thinktecture.IdentityModel.Core Version 1.2.0

You can refer to the previous post if you want to know what each package is responsible for. The package named “System.IdentityModel.Tokens.Jwt” is responsible for validating, parsing and generating JWT tokens. As well we’ve used the package “Thinktecture.IdentityModel.Core” which contains class named “HmacSigningCredentials”  which will be used to facilitate creating signing keys.

Step 1.3: Add Owin “Startup” Class:

Right click on your project then add a new class named “Startup”. It will contain the code below:

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            // Web API routes
            config.MapHttpAttributeRoutes();
            
            ConfigureOAuth(app);
            
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            
            app.UseWebApi(config);

        }

        public void ConfigureOAuth(IAppBuilder app)
        {

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                //For Dev enviroment only (on production should be AllowInsecureHttp = false)
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/oauth2/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
                Provider = new CustomOAuthProvider(),
                AccessTokenFormat = new CustomJwtFormat("http://jwtauthzsrv.azurewebsites.net")
            };

            // OAuth 2.0 Bearer Access Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);

        }
    }

Here we’ve created new instance from class “OAuthAuthorizationServerOptions” and set its option as the below:

  • The path for generating JWT will be as :”http://jwtauthzsrv.azurewebsites.net/oauth2/token”.
  • We’ve specified the expiry for token to be 30 minutes
  • We’ve specified the implementation on how to validate the client and Resource owner user credentials in a custom class named “CustomOAuthProvider”.
  • We’ve specified the implementation on how to generate the access token using JWT formats, this custom class named “CustomJwtFormat” will be responsible for generating JWT instead of default access token using DPAPI, note that both are using bearer scheme.

We’ll come to the implementation of both class later in the next steps.

Step 1.4: Resource Server (Audience) Registration:

Now we need to configure our Authorization server to allow registering Resource server(s) (Audience), this step is very important because we need a way to identify which Resource server (Audience) is requesting the JWT token, so the Authorization server will be able to issue JWT token for this audience only.

The minimal needed information to register a Recourse server into an Authorization server are a unique Client Id, and shared symmetric key. For the sake of keeping this tutorial simple I’m persisting those information into a volatile dictionary so the values for those Audiences will be removed from the memory if IIS reset toke place, for production scenario you need to store those values permanently on a database.

Now add new folder named “Entities” then add new class named “Audience” inside this class paste the code below:

public class Audience
    {
        [Key]
        [MaxLength(32)]
        public string ClientId { get; set; }
        
        [MaxLength(80)]
        [Required]
        public string Base64Secret { get; set; }
        
        [MaxLength(100)]
        [Required]
        public string Name { get; set; }
    }

Then add new folder named “Models” the add new class named “AudienceModel” inside this class paste the code below:

public class AudienceModel
    {
        [MaxLength(100)]
        [Required]
        public string Name { get; set; }
    }

Now add new class named “AudiencesStore” and paste the code below:

public static class AudiencesStore
    {
        public static ConcurrentDictionary<string, Audience> AudiencesList = new ConcurrentDictionary<string, Audience>();
        
        static AudiencesStore()
        {
            AudiencesList.TryAdd("099153c2625149bc8ecb3e85e03f0022",
                                new Audience { ClientId = "099153c2625149bc8ecb3e85e03f0022", 
                                                Base64Secret = "IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw", 
                                                Name = "ResourceServer.Api 1" });
        }

        public static Audience AddAudience(string name)
        {
            var clientId = Guid.NewGuid().ToString("N");

            var key = new byte[32];
            RNGCryptoServiceProvider.Create().GetBytes(key);
            var base64Secret = TextEncodings.Base64Url.Encode(key);

            Audience newAudience = new Audience { ClientId = clientId, Base64Secret = base64Secret, Name = name };
            AudiencesList.TryAdd(clientId, newAudience);
            return newAudience;
        }

        public static Audience FindAudience(string clientId)
        {
            Audience audience = null;
            if (AudiencesList.TryGetValue(clientId, out audience))
            {
                return audience;
            }
            return null;
        }
    }

Basically this class acts like a repository for the Resource servers (Audiences), basically it is responsible for two things, adding new audience and finding exiting one.

Now if you take look on method “AddAudience” you will notice that we’ve implemented the following:

  • Generating random string of 32 characters as an identifier for the audience (client id).
  • Generating 256 bit random key using the “RNGCryptoServiceProvider” class then base 64 URL encode it, this key will be shared between the Authorization server and the Resource server only.
  • Add the newly generated audience to the in-memory “AudiencesList”.
  • The “FindAudience” method is responsible for finding an audience based on the client id.
  • The constructor of the class contains fixed audience for the demo purpose.

Lastly we need to add an end point in our Authorization server which allow registering new Resource servers (Audiences), so add new folder named “Controllers” then add new class named “AudienceController” and paste the code below:

[RoutePrefix("api/audience")]
    public class AudienceController : ApiController
    {
        [Route("")]
        public IHttpActionResult Post(AudienceModel audienceModel)
        {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }

            Audience newAudience = AudiencesStore.AddAudience(audienceModel.Name);

            return Ok<Audience>(newAudience);

        }
    }

This end point can be accessed by issuing HTTP POST request to the URI http://jwtauthzsrv.azurewebsites.net/api/audience as the image below, notice that the Authorization server is responsible for generating the client id and the shared symmetric key. This symmetric key should not be shared with any party except the Resource server (Audience) requested it.

Note: In real world scenario the Resource server (Audience) registration process won’t be this trivial, you might go through workflow approval. Sharing the key will take place using a secure admin portal, as well you might need to provide the audience with the ability to regenerate the key in case it get compromised.

Register Audience

Step 1.5: Implement the “CustomOAuthProvider” Class

Now we need to implement the code responsible for issuing JSON Web Token when the requester issue HTTP POST request to the URI: http://jwtauthzsrv.azurewebsites.net/oauth2/token the request will look as the image below, notice how we are setting the client id for for the Registered resource (audience) from the previous step using key (client_id).

Issue JWT

To implement this we need to add new folder named “Providers” then add new class named “CustomOAuthProvider”, paste the code snippet below:

public class CustomOAuthProvider : OAuthAuthorizationServerProvider
    {

        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            string clientId = string.Empty;
            string clientSecret = string.Empty;
            string symmetricKeyAsBase64 = string.Empty;

            if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
            {
                context.TryGetFormCredentials(out clientId, out clientSecret);
            }

            if (context.ClientId == null)
            {
                context.SetError("invalid_clientId", "client_Id is not set");
                return Task.FromResult<object>(null);
            }

            var audience = AudiencesStore.FindAudience(context.ClientId);

            if (audience == null)
            {
                context.SetError("invalid_clientId", string.Format("Invalid client_id '{0}'", context.ClientId));
                return Task.FromResult<object>(null);
            }
            
            context.Validated();
            return Task.FromResult<object>(null);
        }

        public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {

            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

            //Dummy check here, you need to do your DB checks against memebrship system http://bit.ly/SPAAuthCode
            if (context.UserName != context.Password)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect");
                //return;
                return Task.FromResult<object>(null);
            }

            var identity = new ClaimsIdentity("JWT");

            identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
            identity.AddClaim(new Claim("sub", context.UserName));
            identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
            identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));

            var props = new AuthenticationProperties(new Dictionary<string, string>
                {
                    {
                         "audience", (context.ClientId == null) ? string.Empty : context.ClientId
                    }
                });

            var ticket = new AuthenticationTicket(identity, props);
            context.Validated(ticket);
            return Task.FromResult<object>(null);
        }
    }

As you notice this class inherits from class “OAuthAuthorizationServerProvider”, we’ve overridden two methods “ValidateClientAuthentication” and “GrantResourceOwnerCredentials”

  • The first method “ValidateClientAuthentication” will be responsible for validating if the Resource server (audience) is already registered in our Authorization server by reading the client_id value from the request, notice that the request will contain only the client_id without the shared symmetric key. If we take the happy scenario and the audience is registered we’ll mark the context as a valid context which means that audience check has passed and the code flow can proceed to the next step which is validating that resource owner credentials (user who is requesting the token).
  • The second method “GrantResourceOwnerCredentials” will be responsible for validating the resource owner (user) credentials, for the sake of keeping this tutorial simple I’m considering that each identical username and password combination are valid, in read world scenario you will do your database checks against membership system such as ASP.NET Identity, you can check this in the previous post.
  • Notice that we are setting the authentication type for those claims to “JWT”, as well we are passing the the audience client id as a property of the “AuthenticationProperties”, we’ll use the audience client id in the next step.
  • Now the JWT access token will be generated when we call “context.Validated(ticket), but we still need to implement the class “CustomJwtFormat” we talked about in step 1.3.

Step 1.5: Implement the “CustomJwtFormat” Class

This class will be responsible for generating the JWT access token, so what we need to do is to add new folder named “Formats” then add new class named “CustomJwtFormat” and paste the code below:

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
    {
        private const string AudiencePropertyKey = "audience";

        private readonly string _issuer = string.Empty;

        public CustomJwtFormat(string issuer)
        {
            _issuer = issuer;
        }

        public string Protect(AuthenticationTicket data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;

            if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");

            Audience audience = AudiencesStore.FindAudience(audienceId);

            string symmetricKeyAsBase64 = audience.Base64Secret;
  
            var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);

            var signingKey = new HmacSigningCredentials(keyByteArray);

            var issued = data.Properties.IssuedUtc;
            var expires = data.Properties.ExpiresUtc;

            var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);

            var handler = new JwtSecurityTokenHandler();

            var jwt = handler.WriteToken(token);

            return jwt;
        }

        public AuthenticationTicket Unprotect(string protectedText)
        {
            throw new NotImplementedException();
        }
    }

What we’ve implemented in this class is the following:

  • The class “CustomJwtFormat” implements the interface “ISecureDataFormat<AuthenticationTicket>”, the JWT generation will take place inside method “Protect”.
  • The constructor of this class accepts the “Issuer” of this JWT which will be our Authorization server, this can be string or URI, in our case we’ll fix it to URI with the value “http://jwtauthzsrv.azurewebsites.net”
  • Inside “Protect” method we are doing the following:
    1. Reading the audience (client id) from the Authentication Ticket properties, then getting this audience from the In-memory store.
    2. Reading the Symmetric key for this audience and Base64 decode it to byte array which will be used to create a HMAC265 signing key.
    3. Preparing the raw data for the JSON Web Token which will be issued to the requester by providing the issuer, audience, user claims, issue date, expiry date, and the signing Key which will sign the JWT payload.
    4. Lastly we serialize the JSON Web Token to a string and return it to the requester.
  • By doing this requester for an access token from our Authorization server will receive a signed token which contains claims for a certain resource owner (user) and this token intended to certain Resource server (audience) as well.

So if we need to request a JWT from our Authorization server for a user named “SuperUser” that needs to access the Resource server (audience) “099153c2625149bc8ecb3e85e03f0022″, all we need to do is to issue HTTP POST to the token end point (http://jwtauthzsrv.azurewebsites.net/oauth2/token) as the image below:

Issue JWT2

The result for this will be the below JSON Web Token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6IlN1cGVyVXNlciIsInN1YiI6IlN1cGVyVXNlciIsInJvbGUiOlsiTWFuYWdlciIsIlN1cGVydmlzb3IiXSwiaXNzIjoiaHR0cDovL2p3dGF1dGh6c3J2LmF6dXJld2Vic2l0ZXMubmV0IiwiYXVkIjoiMDk5MTUzYzI2MjUxNDliYzhlY2IzZTg1ZTAzZjAwMjIiLCJleHAiOjE0MTQzODEyODgsIm5iZiI6MTQxNDM3OTQ4OH0.pZffs_TSXjgxRGAPQ6iJql7NKfRjLs1WWSliX5njSYU

There is an online JWT debugger tool named jwt.io that allows you to paste the encoded JWT and decode it so you can interpret the claims inside it, so open the tool and paste the JWT above and you should receive response as the image below, notice that all the claims are set properly including the iss, aud, sub,role, etc…

One thing to notice here that there is red label which states that the signature is invalid, this is true because this tool doesn’t know about the shared symmetric key issued for the audience (099153c2625149bc8ecb3e85e03f0022).

So if we decided to share this symmetric key with the tool and paste the key in the secret text box; we should receive green label stating that signature is valid, and this is identical to the implementation we’ll see in the Resource server when it receives a request containing a JWT.

jwtio

Now the Authorization server (Token issuer) is able to register audiences and issue JWT tokens, so let’s move to adding a Resource server which will consume the JWT tokens.

Section 2: Building the Resource Server (Audience)

Step 2.1: Creating the Resource Server Web API Project

Add a new ASP.NET Web application named “ResourceServer.Api”, the selected template for the project will be “Empty” template with no core dependencies. Notice that the authentication is set to “No Authentication”.

Step 2.2: Installing the needed NuGet Packages:

Open package manger console and install the below Nuget packages:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.Jwt -Version 3.0.0

The package “Microsoft.Owin.Security.Jwt” is responsible for protecting the Resource server resources using JWT, it only validate and de-serialize JWT tokens.

Step 2.3: Add Owin “Startup” Class:

Right click on your project then add a new class named “Startup”. It will contain the code below:

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            config.MapHttpAttributeRoutes();

            ConfigureOAuth(app);

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
           
            app.UseWebApi(config);

        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            var issuer = "http://jwtauthzsrv.azurewebsites.net";
            var audience = "099153c2625149bc8ecb3e85e03f0022";
            var secret = TextEncodings.Base64Url.Decode("IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw");

            // Api controllers with an [Authorize] attribute will be validated with JWT
            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { audience },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                    }
                });

        }
    }

This is the most important step in configuring the Resource server to trust tokens issued by our Authorization server (http://jwtauthzsrv.azurewebsites.net), notice how we are providing the values for the issuer, audience (client id), and the shared symmetric secret we obtained once we registered the resource with the authorization server.

By providing those values to JwtBearerAuthentication middleware, this Resource server will be able to consume only JWT tokens issued by the trusted Authorization server and issued for this audience only.

Note: Always store keys in config files not directly in source code.

Step 2.4: Add new protected controller

Now we want to add a controller which will serve as our protected resource, this controller will return list of claims for the authorized user, those claims for sure are encoded within the JWT we’ve obtained from the Authorization Server. So add new controller named “ProtectedController” under “Controllers” folder and paste the code below:

[Authorize]
    [RoutePrefix("api/protected")]
    public class ProtectedController : ApiController
    {
        [Route("")]
        public IEnumerable<object> Get()
        {
            var identity = User.Identity as ClaimsIdentity;

            return identity.Claims.Select(c => new
            {
                Type = c.Type,
                Value = c.Value
            });
        }
    }

Notice how we attribute the controller with [Authorize] attribute which will protect this resource and only will authentic HTTP GET requests containing a valid JWT access token, with valid I mean:

  • Not expired JWT.
  • JWT issued by our Authorization server (http://jwtauthzsrv.azurewebsites.net).
  • JWT issued for the audience (099153c2625149bc8ecb3e85e03f0022) only.

Conclusion

Using signed JSON Web Tokens facilitates and standardize the way of separating the Authorization server and the Resource server, no more need for unifying machineKey values nor having the risk of sharing the “decryptionKey” and “validationKey” key values among different Resource servers.

Keep in mind that the JSON Web Token we’ve created in this tutorial is signed only, so do not put any sensitive information in it :)

The source code for this tutorial is available on GitHub.

That’s it for now folks, hopefully this short walk through helped in understanding how we can configure the Authorization Server to issue JWT and how we can consume them in a Resource Server.

If you have any comment, question or enhancement please drop me a comment, I do not mind if you star the GitHub Repo too :)

Follow me on Twitter @tjoudeh

References

The post JSON Web Token in ASP.NET Web API 2 using Owin appeared first on Bit of Technology.

Getting started with ASP.NET 5 MVC 6 Web API & Entity Framework 7

$
0
0

One of the main new features of ASP.NET 5 is unifying the programming model and combining MVC, Web API, and Web Pages in single framework called MVC 6. In previous versions of ASP.NET (MVC 4, and MVC 5) there were overlapping in the features between MVC and Web API frameworks, but the concrete implementation for both frameworks was totally different, with ASP.NET 5 the merging between those different frameworks will make it easier to develop modern web applications/HTTP services and increase code reusability.

The source code for this tutorial is available on GitHub.

Getting started with ASP.NET 5 MVC 6 Web API & Entity Framework 7

In this post I’ve decided to give ASP.NET 5 – MVC 6 Web API a test drive, I’ll be building a very simple RESTful API from scratch by using MVC 6 Web API and the new Entity Framework 7, so we will learn the following:

  • Using the ASP.NET 5 empty template to build the Web API from scratch.
  • Overview of the new project structure in VS 2015 and how to use the new dependency management tool.
  • Configuring ASP.NET 5 pipeline to add only the components needed for our Web API.
  • Using EF 7 commands and the K Version Manager (KVM) to initialize and apply DB migrations.

To follow along with this post you need to install VS 2015 preview edition or you can provision a virtual machine using Azure Images as they have an Image with VS 2015 preview installed.

Step 1: Creating an empty web project

Open VS 2015 and select New Web Project (ASP.NET Web Application) as the image below, do not forget to set the .NET Framework to 4.5.1. You can name the project “Registration_MVC6WebApi”.

ASPNET5 New project

Now we’ll select the template named “ASP.NET 5 Empty” as the image below, this template is an empty template with no core dependencies on any framework.

MVC 6 Web API Project Template

Step 2: Adding the needed dependencies

Once the project is created you will notice that there is a file named “project.json” this file contains all your project settings along with a section for managing project dependencies on other frameworks/components.

We’ve used to manage packages/dependencies by using NuGet package manager, and you can do this with the new enhanced NuGet package manager tool which ships with VS 2015, but in our case we’ll add all the dependencies using the “project.json” file and benefit from the IntelliSense provided as the image below:

NuGet IntelliSense

So we will add the dependencies needed to configure our Web API, so open file “project.json” and replace the section “dependencies” with the section below:

"dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
        "EntityFramework": "7.0.0-beta1",
        "EntityFramework.SqlServer": "7.0.0-beta1",
        "EntityFramework.Commands": "7.0.0-beta1",
        "Microsoft.AspNet.Mvc": "6.0.0-beta1",
        "Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
        "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta1"
    }

The use for each dependency we’ve added as the below:

  • Microsoft.AspNet.Server.IIS: We want to host our Web API using IIS, so this package is needed. If you are planning to self-host your Web API then no need to add this package.
  • EntityFramework & EntityFramework.SqlServer: Our data provider for the Web API will be SQL Server. Entity Framework 7 can be configured to work with different data providers and not only relational databases, the data providers supported by EF 7 are: SqlServer, SQLite, AzureTableStorage, and InMemory. More about EF 7 data providers here.
  • EntityFramework.Commands: This package will be used to make the DB migrations command available in our Web API project by using KVM, more about this later in the post.
  • Microsoft.AspNet.Mvc: This is the core package which adds all the needed components to run Web API and MVC.
  • Microsoft.AspNet.Diagnostics: Basically this package will be used to display a nice welcome page when you request the base URI for the API in a browser. You can ignore this if you want, but it will be nice to display welcoming page instead of the 403 page displayed for older Web API 2.
  • Startup
  • Microsoft.Framework.ConfigurationModel.Json: This package is responsible to load and read the configuration file named “config.json”. We’ll add this file in a later step. This file is responsible to setup the “IConfiguration” object. I recommend to read this nice post about ASP.NET 5 new config files.

Last thing we need to add to the file “project.json” is a section named “commands” as the snippet below:

"commands": {
        "ef": "EntityFramework.Commands"
}

We’ve added short prefix “ef” for EntityFramework.Commands which will allow us to write EF commands such as initializing and applying DB migrations using KVM.

Step 3: Adding config.json configuration file

Now right click on your project and add new item of type “ASP.NET Configuration File” and name it “config.json”, you can think of this file as a replacement for the legacy Web.config file, for now this file will contain only our connection string to our SQL DB, I’m using SQL Express here and you can change this to your preferred SQL server.

{
    "Data": {
        "DefaultConnection": {
            "Connectionstring": "Data Source=.\\sqlexpress;Initial Catalog=RegistrationDB;Integrated Security=True;"
        }
    }
}

Note: This is a JSON file that’s why we are using escape characters in the connection string.

Step 4: Configuring the ASP.NET 5 pipeline for our Web API

This is the class which is responsible for adding the components needed in our pipeline, currently with the ASP.NET 5 empty template, the class is empty and our web project literally does nothing, I’ll add all the code in our Startup class at once then describe what each line of code is responsible for, so open file Startup.cs and paste the code below:

using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Registration_MVC6WebApi.Models;

namespace Registration_MVC6WebApi
{
    public class Startup
    {
        public static IConfiguration Configuration { get; set; }

        public Startup(IHostingEnvironment env)
        {
            // Setup configuration sources.
            Configuration = new Configuration().AddJsonFile("config.json").AddEnvironmentVariables();
        }
        public void ConfigureServices(IServiceCollection services)
        {
            // Add EF services to the services container.
            services.AddEntityFramework().AddSqlServer().AddDbContext<RegistrationDbContext>();

            services.AddMvc();

            //Resolve dependency injection
            services.AddScoped<IRegistrationRepo, RegistrationRepo>();
            services.AddScoped<RegistrationDbContext, RegistrationDbContext>();
        }
        public void Configure(IApplicationBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
            app.UseMvc();

            app.UseWelcomePage();

        }
    }
}

What we’ve implemented in this class is the following:

  • The constructor for this class is responsible to read the settings in the configuration file “config.json” that we’ve defined earlier, currently we have only the connection string. So the static object “Configuration” contains this setting which we’ll use in the coming step.
  • The method “ConfigureServices” accepts parameter of type “IServiceCollection”, this method is called automatically when starting up the project, as well this is the core method responsible to register components in our pipeline, so the components we’ve registered are:
    • We’ve added “EntityFramework” using SQL Server as our data provider for the database context named “RegistrationDBContext”. We’ll add this DB context in next steps.
    • Added the MVC component to our pipeline so we can use MVC and Web API.
    • Lastly and one of the nice out of the box features which has been added to ASP.NET 5 is Dependency Injection without using any external IoC containers, notice how we are creating single instance scoped instance of our “IRegistrationRepo” by calling 
      services.AddScoped<IRegistrationRepo, RegistrationRepo>();
      . This instance will be available for the entire lifetime of our application life time of the request, we’ll implement the classes “IRegistrationRepo” and “RegistrationRepo” in next steps of this post. There is a nice post about ASP.NET 5 dependency injection can be read here. (Update by Nick Nelson to use Scoped injection instead of using Singleton instance because DbContext is not thread safe).
  • Lastly the method “Configure” accepts parameter of type “IApplicationBuilder”, this method configures the pipeline to use MVC and show the welcome page. Do not ask me why we have to call “AddMvc” and “UseMvc” and what is the difference between both :) I would like to hear an answer if someone knows the difference or maybe this will be changed in the coming release of ASP.NET 5. (Update: Explanation of this pattern in the comments section).

Step 5: Adding Models, Database Context, and Repository

Now we’ll add a file named “Course” which contains two classes: “Course” and “CourseStatusModel”, those classes will represents our domain data model, so for better code organizing add new folder named “Models” then add the new file containing the the code below:

using System;
using System.ComponentModel.DataAnnotations;

namespace Registration_MVC6WebApi.Models
{
    public class Course
    {
        public int Id { get; set; }
        [Required]
        [StringLength(100, MinimumLength = 5)]
        public string Name { get; set; }
        public int Credits { get; set; }
    }

    public class CourseStatusModel
    {
        public int Id { get; set; }
        public string Description { get; set; }
    }
}

Now we need to add Database context class which will be responsible to communicate with our database, so add new class and name it “RegistrationDbContext” then paste the code snippet below:

using Microsoft.Data.Entity;
using System;
using Microsoft.Data.Entity.Metadata;

namespace Registration_MVC6WebApi.Models
{
    public class RegistrationDbContext :DbContext
    {
        public DbSet<Course> Courses { get; set; }

        protected override void OnConfiguring(DbContextOptions options)
        {
            options.UseSqlServer(Startup.Configuration.Get("Data:DefaultConnection:ConnectionString"));
        }
    }
}

Basically what we’ve implemented here is adding our Courses data model as DbSet so it will represent a database table once we run the migrations, note that there is a new method named “OnConfiguration” where we can override it so we’ll be able to specify the data provider which needs to work with our DB context.

In our case we’ll use SQL Server, the constructor for “UseSqlServer” extension method accepts a parameter of type connection string, so we’ll read it from our “config.json” file by specifying the key “Data:DefaultConnection:ConnectionString” for the “Configuration” object we’ve created earlier in Startup class.

Note: This is not the optimal way to set the connection string, there are MVC6 examples out there using this way, but for a reason it is not working with me, so I followed my way.

Lastly we need to add the interface “IRegistrationRepo” and the implementation for this interface “RegistrationRepo”, so add two new files under “Models” folder named “IRegistrationRepo” and “RegistrationRepo” and paste the two code snippets below:

using System;
using System.Collections;
using System.Collections.Generic;

namespace Registration_MVC6WebApi.Models
{
    public interface IRegistrationRepo
    {
        IEnumerable<Course> GetCourses();
        Course GetCourse(int courseId);
        Course AddCourse(Course course);
        bool DeleteCourse(int courseId);
    }
}

using System;
using System.Collections.Generic;
using System.Linq;


namespace Registration_MVC6WebApi.Models
{
    public class RegistrationRepo : IRegistrationRepo
    {
        private readonly RegistrationDbContext _db;

        public RegistrationRepo(RegistrationDbContext db)
        {
            _db = db;
        }
        public Course AddCourse(Course course)
        {
            _db.Courses.Add(course);

            if (_db.SaveChanges() > 0)
            {
                return course;
            }
            return null;

        }

        public bool DeleteCourse(int courseId)
        {
            var course = _db.Courses.FirstOrDefault(c => c.Id == courseId);
            if (course != null)
            {
                _db.Courses.Remove(course);
                return _db.SaveChanges() > 0;
            }
            return false;
        }

        public Course GetCourse(int courseId)
        {
            return _db.Courses.FirstOrDefault(c => c.Id == courseId);
        }

        public IEnumerable<Course> GetCourses()
        {
            return _db.Courses.AsEnumerable();
        }
    }
}

The implementation here is fairly simple, what worth noting here is how we’ve passed “RegistrationDbContext” as parameter for our “RegistrationRepo” constructor so we’ve implemented Constructor Injection, this will not work if we didn’t configure this earlier in our “Startup” class.

Step 6: Installing KVM (K Version Manager)

After we’ve added our Database context and our domain data models, we can use migrations to create the database, with previous version of ASP.NET we’ve used NuGet package manager for these type of tasks, but with ASP.NET 5 we can use command prompt using various K* commands.

What is KVM (K Version Manager)?  KVM is a Powershell script used to get the runtime and manage multiple versions of it being on the machine at the same time, you can read more about it here.

Now to install KVM for the first time you have to do the following steps:

1. Open a command prompt with Run as administrator.
2. Run the following command:

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

3. The script installs KVM for the current user.
4. Exit the command prompt window and start another as an administrator (you need to start a new command prompt to get the updated path environment).
5. Upgrade KVM with the following command:

KVM upgrade

We are ready now to run EF migrations as the step below:

Step 7: Initializing and applying migrations for our database

Now our command prompt is ready to understand K commands and Entity Framework commands, first step to do is to change the directory to the project directory. The project directory contains the “project.json” file as the image below:

EF7 Migrations
So in the command prompt we need to run the 2 following commands:

k ef migration add initial
k ef migration apply

Basically the first command will add migration file with the name format (<date>_<migration name>) so we’ll end up having file named “201411172303154_initial.cs” under folder named “Migrations” in our project. This auto generated file contains the code needed to to add our Courses table to our database, the newly generated files will show up under your project as the image below:

EF7 Migrations 2
The second command will apply those migrations and create the database for us based on the connection string we’ve specified earlier in file “config.json”.

Note: the “ef” command comes from the settings that we’ve specified earlier in file “project.json” under section “commands”.

Step 8: Adding GET methods for Courses Controller

The controller is a class which is responsible to handle HTTP requests, with ASP.NET 5 our Web API controller will inherit from “Controller” class not anymore from “ApiController”, so add new folder named “Controllers” then add new controller named “CoursesController” and paste the code below:

using Microsoft.AspNet.Mvc;
using Registration_MVC6WebApi.Models;
using System;
using System.Collections.Generic;

namespace Registration_MVC6WebApi.Controllers
{
    [Route("api/[controller]")]
    public class CoursesController : Controller
    {
        private IRegistrationRepo _registrationRepo;

        public CoursesController(IRegistrationRepo registrationRepo)
        {
            _registrationRepo = registrationRepo;
        }

        [HttpGet]
        public IEnumerable<Course> GetAllCourses()
        {
            return _registrationRepo.GetCourses();
        }

        [HttpGet("{courseId:int}", Name = "GetCourseById")]
        public IActionResult GetCourseById(int courseId)
        {
            var course = _registrationRepo.GetCourse(courseId);
            if (course == null)
            {
                return HttpNotFound();
            }

            return new ObjectResult(course);
        }

    }
}

What we’ve implemented in the controller class is the following:

  • The controller is attribute with Route attribute as the following
    [Route("api/[controller]")]
    so any HTTP requests that match the template are routed to the controller. The “[controller]” part in the template URL means to substitute the controller class name, minus the “Controller” suffix. In our case and for “CoursesController” class, the route template is “api/courses”.
  • We’ve defined two HTTP GET methods, the first one “GetAllCourses” is attributed with “[HttpGet]” and it returns a .NET object which is serialized in the body of the response using the default JSON format.
  • The second HTTP GET method “GetCourseById” is attributed with “[HttpGet]“. For this method we’ve specified a constraint on the parameter “courseId”, the parameter should be of integer data type. As well we’ve specified a name for this method “GetCourseById” which we’ll use in the next step. Last thing this method returns object of type IActionResult which gives us flexibility to return different actions results based on our logic, in our case we will return HttpNotFound if the course does not exist or we can return serialized JSON object of the course when the course is found.
  • Lastly notice how we are passing the “IRegistrationRepo” as a constructor for our CoursesController, by doing this we are implementing Constructor Injection.

Step 9: Adding POST and DELETE methods for Courses Controller

Now we want to implement another two HTTP methods which allow us to add new Course or delete existing one, so open file “CoursesController” and paste the code below:

[HttpPost]
public IActionResult AddCourse([FromBody] Course course)
{
	if (!ModelState.IsValid)
	{
		Context.Response.StatusCode = 400;
		return new ObjectResult(new CourseStatusModel { Id = 1 , Description= "Course model is invalid" });
	}
	else
	{
	   var addedCourse =  _registrationRepo.AddCourse(course);

		if (addedCourse != null)
		{
			string url = Url.RouteUrl("GetCourseById", new { courseId = course.Id }, Request.Scheme, Request.Host.ToUriComponent());

			Context.Response.StatusCode = 201;
			Context.Response.Headers["Location"] = url;
			return new ObjectResult(addedCourse);
		}
		else
		{
			Context.Response.StatusCode = 400;
			return new ObjectResult(new CourseStatusModel { Id = 2, Description = "Failed to save course" });
		}
	   
	}
}

What we’ve implemented here is the following:

  • For method “AddCourse”:
    • Add new HTTP POST method which is responsible to create new Course, this method accepts Course object which is coming from the request body then Web API framework will deserialize this to CLR Course object.
    • If the course object is not valid (i.e. course name not set) then we’ll return HTTP 400 status code and an object containing description of the validation error. Thanks for Yishai Galatzer for spotting this out because I was originally returning response of type “text/plain” always regarding the “Accept” header value set by the client. The point below contains the fix.
    • If the course object is not valid (i.e. course name not set) then we’ll return HTTP 400 status code, and in the response body we’ll return an instance of a POCO class(CourseStatusModel) containing fictional Id and description of the validation error.
    • If the course created successfully then we’ll build a location URI which points to our new created course i.e. (/api/courses/4) and set this URI in the “Location” header for the response.
    • Lastly we are returning the created course object in the response body.
  • For method “DeleteCourse”:
    • Add new HTTP DELETE method which is responsible for deleting existing course, this method accepts integer courseId.
    • If the course has been deleted successfully we’ll return HTTP status 204 (No content)
    • If the passed courseId doesn’t exists we will return HTTP status 404.

Note: I believe that the IhttpActionResult response which got introduced in Web API 2 is way better than IActionResult, please drop me a comment if someone knows how to use IhttpActionResult with MVC6.

The source code for this tutorial is available on GitHub.

That’s all for now folks! I’m still learning the new features in ASP.NET 5, please drop me a comment if you have better way implementing this tutorial or you spotted something that could be done in a better way.

Follow me on Twitter @tjoudeh

References

The post Getting started with ASP.NET 5 MVC 6 Web API & Entity Framework 7 appeared first on Bit of Technology.


AngularJS Authentication Using Azure Active Directory Authentication Library (ADAL)

$
0
0

In my previous post Secure ASP.NET Web API 2 using Azure Active Directory I’ve covered how to protect Web API end points using bearer tokens issued by Azure Active Directory, and how to build a desktop application which acts as a Client. This Client gets the access token from the Authorization Server (Azure Active Directory) then use this bearer access token to call a protected resource exits in our Resource Server (ASP.NET Web API).

Azure Active Directory Web Api

Initially I was looking to build the client application by using AngularJS (SPA) but I failed to do so because at the time of writing the previous post Azure Active Directory Authentication Library (ADAL) didn’t support OAuth 2.0 Implicit Grant which is the right OAuth grant that should be used when building applications running in browsers.

The live AngularJS demo application is hosted on Azure (User: ADAL@taiseerjoudeharamex.onmicrosoft.com/ Pass: AngularJS!!), the source code for this tutorial on GitHub.

So I had discussion with Vittorio Bertocci and Attila Hajdrik on twitter about this limitation in ADAL and Vittorio promised that this feature is coming soon, and yes ADAL now supports OAuth 2.0 Implicit Grant and integrating it with your AngularJS is very simple, I recommend you to watch Vittorio video introduction on Channel 9 before digging into this tutorial.

AngularJS Authentication Using Azure Active Directory Authentication Library (ADAL)

What is OAuth 2.0 Implicit Grant?

In simple words the implicit grant is optimized for public clients (can not store secrets) and those clients are built using JavaScript and they run in browsers. There is no client authentication happening here and the only factors should be presented to obtain an access token is the resource owner credentials and pre-registration for the redirection URI with the Authorization server. This redirect URI will be used to receive the access token issued by the Authorization server in a form of URI fragment.

What we’ll build in this tutorial?

In this tutorial we’ll build simple SPA application using AngularJS along with ADAL for JS which provides a very comprehensive abstraction for the Implicit Grant we described earlier. This SPA will communicate with a protected Resource Server (Web API) to get list of orders, and will request the access token from our Authorization Server (Azure Active Directory).

In order to follow along with this tutorial I’ve created a sample skeleton project which contains the basic code needed to run our AngularJS application and the Web API without adding any feature related to the security. So I recommend you to download it first so you can follow along with the steps below.

The NuGet packages I used in this project are:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Security.ActiveDirectory -Version 3.0.0

Step 1: Register the Web API into Azure Active Directory

Open Azure Management Portal in order to register our Web API as an application in our Azure Active Directory, to do so and after your successful login to Azure Management Portal, click on “Active Directory” in the left hand navigation menu, choose your active directory tenant you want to register your Web API with, then select the “Applications” tab, then click on the add icon at bottom of the page. Once the modal window shows as the image below select “Add an application my organization is developing”.
Azure New App
Then a wizard of 2 steps will show up asking you to select the type of the app you want to add, in our case we are currently adding a Web API so select “Web Application and/or Web API”, then provide a name for the application, in my case I’ll call it “AngularJSAuthADAL”, then click next.
Azure App Name
In the second step as the image below we need to fill two things, the Sign-On URL which is usually will be your base URL for your Web API, so in my case it will be “http://localhost:10966″, and the second field APP ID URI will usually be filled with a URI that Azure AD can use for this app, it usually take the form of “http://<your_AD_tenant_name>/<your_app_friendly_name>” so we will replace this with the correct values for my app and will be filed as “http://taiseerjoudeharamex.onmicrosoft.com/AngularJSAuthADAL” then click OK.

Azure App Properties

Step 2: Enable Implicit Grant for the Application

After our Web API has been added to Azure Active Directory apps, we need enable the implicit grant. To do so we need to change our Web API configuring using the application manifest. Basically the application manifest is a JSON file that represents our application identity configuration.

So as the image below and after you navigate to the app we’ve added click on “Manage Manifest” icon at the bottom of the page, then click on “Download Manifest”.

Download Manifest

Open the downloaded JSON application manifest file and change the value of “oauth2AllowImplicitFlow” node to “true“.  As well notice how the “replyUrls” array contains the URL which we want the token response returned to. You can read more about Web API configuration here.

After we apply this change, save the application manifest file locally then upload it again to your app using the “Upload Manifest” feature.

Step 3: Configure Web API to Accept Bearer Tokens Issued by Azure AD

Now and if you have downloaded the skeleton project right click on it and click on build to download the needed Nuget packages, if you want you can run the application and a nice SPA will be show up and the orders will be displayed as the image below because we didn’t configure the security part yet.

AngularJS Adal

Now open file “Startup.cs” and paste the code below:

public void ConfigureOAuth(IAppBuilder app)
        {
            app.UseWindowsAzureActiveDirectoryBearerAuthentication(
               new WindowsAzureActiveDirectoryBearerAuthenticationOptions
               {
                   Audience = ConfigurationManager.AppSettings["ida:ClientID"],
                   Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
               });
        }

Basically what we’ve implemented here is simple, we’ve configured the Web API authentication middleware to use “Windows Azure Active Directory Bearer Tokens” for the specified Active Directory “Tenant” and “Audience” (Client Id). Now any API controller lives in this API and attribute with [Authorize] attribute will only accept bearer tokens issued from this specified Active Directory Tenant, any other form of tokens will be rejected.

It is a good practice to store the values for your Audience, Tenant, Secrets, etc… in a configuration file and not to hard-code them, so open the web.config file and add 2 new “appSettings” as the snippet below, the value for the Client Id can be read your Azure App settings.

<appSettings>
    <add key="ida:Tenant" value="taiseerjoudeharamex.onmicrosoft.com" />
    <add key="ida:ClientID" value="1725911b-ad8f-4295-8258-cf95ba9f7ea6" />
  </appSettings>

Step 4: Protect Orders Controller

Now open file “OrdersController” and attribute it with [Authorize] attribute, by doing this any GET request to the path “http://localhost:port/api/orders” will return status code 401 if no token provided in the Authorization header. When you apply this the orders view won’t return any data until we obtain a valid token. Orders controller code will look as the below snippet:

[Authorize]
[RoutePrefix("api/orders")]
public class OrdersController : ApiController
{
	//Rest of code is here
}

Step 5: Download ADAL JavaScript Library

Now it is time to download and use ADAL JS library which will facilitates the AngularJS authentication using the Implicit grant, so after you download the file, open page “Index.html” and add reference to it at the end of the file as the code below:

<!-- 3rd party libraries -->
 <!Other JS references here -->
 <script src="scripts/adal.js"></script>

Step 6: Configure our AngularJS bootstrap file (app.js)

Now open file “app.js” where we’ll inject the ADAL dependencies into our AngularJS module “AngularAuthApp”, so after you open the file change the code in it as the below:

var app = angular.module('AngularAuthApp', ['ngRoute', 'AdalAngular']);

app.config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', function ($routeProvider, $httpProvider, adalAuthenticationServiceProvider) {

    $routeProvider.when("/home", {
        controller: "homeController",
        templateUrl: "/app/views/home.html"
    });

    $routeProvider.when("/orders", {
        controller: "ordersController",
        templateUrl: "/app/views/orders.html",
        requireADLogin: true
    });

    $routeProvider.when("/userclaims", {
        templateUrl: "/app/views/userclaims.html",
        requireADLogin: true
    });

    $routeProvider.otherwise({ redirectTo: "/home" });

    adalAuthenticationServiceProvider.init(
      {
          tenant: 'taiseerjoudeharamex.onmicrosoft.com',
          clientId: '1725911b-ad8f-4295-8258-cf95ba9f7ea6'
      }, $httpProvider);

}]);
var serviceBase = 'http://localhost:10966/';
app.constant('ngAuthSettings', {
    apiServiceBaseUri: serviceBase
});

What we’ve implemented is the below:

  • We’ve injected the “AdalAngular” to our module “AngularAuthApp”.
  • The service “adalAuthenticationServiceProvider” is now available and injected into our App configuration.
  • We’ve set the property “requireADLogin” to “true” for any partial view requires authentication, by doing this if the user requested a protected view, a redirection to Azure AD tenant will take place and the user (resource owner) will be able to enter his AD credentials to authenticate.
  • Lastly, we’ve set the “tenant” and “clientId” values related to our AD Application.

Step 7: Add explicit Login and Logout feature to the SPA

The ADAL Js library provide us with explicit way to login/logout the user by calling “login” function, so to add this open file named “indexController.js” and replace the code existing with the code below:

'use strict';
app.controller('indexController', ['$scope', 'adalAuthenticationService', '$location', function ($scope, adalAuthenticationService, $location) {

    $scope.logOut = function () {
      
        adalAuthenticationService.logOut();
    }

    $scope.LogIn = function () {

        adalAuthenticationService.login();
    }

}]);

Step 8: Hide/Show links based on Authentication Status

For better user experience it will be nice if we hide the login link from the top menu when the user is already logged in, and to hide the logout link when the user is not logged in yet, to do so open file “index.html” and replace the menu items with code snippet below:

<div class="collapse navbar-collapse" data-collapse="!navbarExpanded">
                <ul class="nav navbar-nav navbar-right">
                    <li data-ng-hide="!userInfo.isAuthenticated"><a href="#">Welcome {{userInfo.profile.given_name}}</a></li>
                    <li><a href="#/orders">View Orders</a></li>
                    <li data-ng-hide="!userInfo.isAuthenticated"><a href="" data-ng-click="logOut()">Logout</a></li>
                    <li data-ng-hide="userInfo.isAuthenticated"><a href="" data-ng-click="LogIn()">Login</a></li>
                </ul>
            </div>

Notice that we are depending on object named “userInfo” to read property named “isAuthenticated”, this object is set in the “$rootScope” in ADAL JS library so it is available globally in our AngularJS app.

By completing this step and if we tried to run the application and request the view “orders” or click on “login” link, we will be redirected to our Azure AD tenant to enter user credentials and have an access to the protected view, there is lot of abstraction happening here that needs to be clarified in the section below.

ADAL JavaScrip Flow

  • Once the anonymous user request protected view (view marked with requireADLogin = true ) or hit on login link explicitly, ADAL will trigger login directly as the code highlighted here.
  • The Login in ADAL library means building redirection URI to the configured Azure AD tenant we’ve defined in the “init” method in “app.js” file, the URI will contain random “state” and “nonce” to uniquely identify each request and prevent from any reply requests, as well the value for the “redirect_uri” is set the to current location of the page which should match the value we’ve defined once we registered the application, lastly the “response_type” is set to “id_token” so the authorization server should send back a JWT token contains claims about the user. The redirection URI will look as the below and code for building the redirection URI is highlighted here

https://login.windows.net/taiseerjoudeharamex.onmicrosoft.com/oauth2/authorize?response_type=id_token&client_id=1725911b-ad8f-4295-8258-cf95ba9f7ea6&redirect_uri=http%3A%2F%2Fngadal.azurewebsites.net%2F&state=9cce69d3-af36-4eb4-a882-4e9b7080e90d&x-client-SKU=Js&x-client-Ver=0.0.3&nonce=d4313f89-dc4f-4590-b7fd-9bbc2b340759

  • Now the Azure AD login page will show up for the user, then the user will be prompted to enter his AD credentials as the image blow, assuming he entered credentials correctly, a redirection will take place to the following URI containing the token as part of URI fragment not query string along with the same state and nonce specified by ADAL earlier.

https://ngadal.azurewebsites.net/#/id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtyaU1QZG1Cdng2OHNrVDgtbVBBQjNCc2VlQSJ9.eyJhdWQiOiIxNzI1OTExYi1hZDhmLTQyOTUtODI1OC1jZjk1YmE5ZjdlYTYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC8wODExZmIzMS05M2VkLTRmZWItYTAwOS1kNmUyN2RmYWMxN2IvIiwiaWF0IjoxNDE3NDgwMjc5LCJuYmYiOjE0MTc0ODAyNzksImV4cCI6MTQxNzQ4NDE3OSwidmVyIjoiMS4wIiwidGlkIjoiMDgxMWZiMzEtOTNlZC00ZmViLWEwMDktZDZlMjdkZmFjMTdiIiwiYW1yIjpbInB3ZCJdLCJvaWQiOiI2OTIyYTVlZi01YmMyLTRiYmEtYjI5Yy1kODc0YzQyYjg1OWQiLCJ1cG4iOiJIYW16YUB0YWlzZWVyam91ZGVoYXJhbWV4Lm9ubWljcm9zb2Z0LmNvbSIsInVuaXF1ZV9uYW1lIjoiSGFtemFAdGFpc2VlcmpvdWRlaGFyYW1leC5vbm1pY3Jvc29mdC5jb20iLCJzdWIiOiJxVWU4UUQ4SzdwOF9zTlI5WlhQYWcyOVFCeGZURlhKbTBaVzR0UDdYSEJNIiwiZmFtaWx5X25hbWUiOiJKb3VkZWgiLCJnaXZlbl9uYW1lIjoiSGFtemEiLCJub25jZSI6ImQ1NmEwNDJhLWQzM2YtNGYxYS05ZmYwLTFjMWE1ZDk3YzVmMSIsInB3ZF9leHAiOiI3NDMzNDg5IiwicHdkX3VybCI6Imh0dHBzOi8vcG9ydGFsLm1pY3Jvc29mdG9ubGluZS5jb20vQ2hhbmdlUGFzc3dvcmQuYXNweCJ9.efAp-95yMvhLu--8TfXYwozJsc09OTsB5bneH9bvGzko6uLZj0YloDTIrVtu_SU95hOBpFvma0FOeGmsqre6DBwaLTSJDD9wTYtqmoCGwpTy_cewpS78MJ9aR-IjWx5O6K8Nt90d4ujaco5T-o2EQ4ygPx5Z6vH-sLy8t9NDVER7HtlClhRwj2uDUF-kdihh7lv5w0U7TqHZUtLkBNL2l69yY5F0Jdj0q7m81gNps6nfqfa8aypgmztpPWDJAChvwsD5r58CyGVXPKSp_2CfK0kkWasP6fmLKKi5tGPvjg-wEb2j47UVIgO8v9xIkqg8RGqnZ1lboZKa2FlCs-Jnrw&state=6ac680d1-8b3b-452a-97d2-3deddb4016fc&session_state=2d48f965-e026-4c08-9d38-2cce49ee72cb

Azure AD Login

Note: You can extract the JSON Web token manually and debug it using JWT debugging tool to explore the claims inside it.

  • Now once ADAL JS library receives this call back, it will go and extract the token from the hash fragment, try to decode this token to get user profile and other claims from it (i.e. token expiry), then store the token along with decoded claims in HTML 5 local storage so the token will not vanish if you closed the browser or do full refresh (F5) for your AngularJS application, the implementation is very similar to what we’ve covered earlier in AngularJS authentication post.
  • To be able to access the protected API end points, we need to send the token in the “Authorization” header using bearer scheme, the ADAL JS provides an AngularJS interceptor which is responsible to add the Authorization header to each XHR request if there is token stored in the localStorage, these is very similar to the interceptor we’ve added before in our AngularJS Authentication post.
  • If the user decided to “logout” from the system, then ADAL JS clears all the stored data in the HTML 5 local storage, so no token stored locally, then it issue redirect to the URI: https://login.windows.net/{tenantid}/oauth2/logout which will be responsible to clear the clear any session cookies created by Azure AD tenant, but remember that logging out from the system will not invalidate your token, if you extracted the token manually then it will remain valid until it expires, usually after 1 hour of the issuing time.
  • ADAL JS provides a nice way to renew the token without using grant_type = refresh_token, it tries to renew the token silently by using a hidden iframe which communicates with Azure AD tenant asking for a new token if there is a valid session established by the AD tenant.

The live AngularJS demo application is hosted on Azure (ADAL@taiseerjoudeharamex.onmicrosoft.com/AngularJS!!), the source code for this tutorial on GitHub.

Conclusion

ADAL JS library really simplifies adding OAuth 2.0 Implicit grant to your SPA, it is still on developer preview release so testing it out and providing feedback will be great to enhance it.

If you have any comments or enhancement on this tutorial please drop me comment. Thanks for taking the time to read the post!

Follow me on Twitter @tjoudeh

References

The post AngularJS Authentication Using Azure Active Directory Authentication Library (ADAL) appeared first on Bit of Technology.

Secure ASP.NET Web API using API Key Authentication – HMAC Authentication

$
0
0

Web API Security

Recently I was working on securing ASP.NET Web API HTTP service that will be consumed by a large number of terminal devices installed securely in different physical locations, the main requirement was to authenticate calls originating from those terminal devices to the HTTP service and not worry about the users who are using it. So first thing came to my mind is to use one of the OAuth 2.0 flows which is Resource Owner Password Credentials Flow, but this flow doesn’t fit nicely in my case because the bearer access tokens issued should have expiry time as well they are non revocable by default, so issuing an access token with very long expiry time (i.e one year) is not the right way to do it.

After searching for couple of hours I found out that the right and maybe little bit complex way to implement this is to use HMAC Authentication (Hash-based Message Authentication Code).

The source code for this tutorial is available on GitHub.

What is HMAC Authentication?

It is a mechanism for calculating a message authentication code using a hash function in combination with a shared secret key between the two parties involved in sending and receiving the data (Front-end client and Back-end HTTP service) . The main use for HMAC to verify the integrity, authenticity, and the identity of the message sender.

So in simpler words the server provides the client with a public APP Id and shared secret key (API Key – shared only between server and client), this process happens only the first time when the client registers with the server.

After the client and server agrees on the API Key, the client creates a unique HMAC (hash) representing the request originated from it to the server. It does this by combining the request data and usually it will contain (Public APP Id, request URI, request content, HTTP method, time stamp, and nonce) in order to produce a unique hash by using the API Key. Then the client sends that hash to the server, along with all information it was going to send already in the request.

Once the server revives the request along with the hash from the client, it tries to reconstruct the hash by using the received request data from the client along with the API Key, once the hash is generated on the server, the server will be responsible to compare the hash sent by the client with the regenerated one, if they match then the server consider this request authentic and process it.

Flow of using API Key – HMAC Authentication:

Note: First of all the server should provide the client with a public (APP Id) and shared private secret (API Key), the client responsibility is to store the API Key securely and never share it with other parties.

Flow on the client side:

  1. Client should build a string by combining all the data that will be sent, this string contains the following parameters (APP Id, HTTP method, request URI, request time stamp, nonce, and Base 64 string representation of the request pay load).
  2. Note: Request time stamp is calculated using UNIX time (number of seconds since Jan. 1st 1970) to overcome any issues related to a different timezone between client and server. Nonce: is an arbitrary number/string used only once. More about this later.
  3. Client will hash this large string built in the first step using a hash algorithm such as (SHA256) and the API Key assigned to it, the result for this hash is a unique signature for this request.
  4. The signature will be sent in the Authorization header using a custom scheme such as”amx”. The data in the Authorization header will contain the APP Id, request time stamp, and nonce separated by colon ‘:’. The format for the Authorization header will be like: [Authorization: amx APPId:Signature:Nonce:Timestamp].
  5. Client send the request as usual along with the data generated in step 3 in the Authorization header.

Flow on the server side:

  1. Server receives all the data included in the request along with the Authorization header.
  2. Server extracts the values (APP Id, Signature, Nonce and Request Time stamp) from the Authorization header.
  3. Servers looks for the APP Id in a certain secure repository (DB, Configuration file, etc…) to get the API Key for this client.
  4. Assuming the server was able to look up this APP Id from the repository, it will be responsible to validate if this request is a replay request and reject it, so it will prevent the API from any replay attacks. This is why we’ve used a request time stamp along with nonce generated at the client, and both values have been included into HMAC signature generation. The server will depend on the nonce to check if it was used before within certain acceptable bounds, i.e. 5 minutes. More about this later.
  5. Server will rebuild a string containing the same data received in the request by adhering to the same parameters orders and encoding followed in the client application, usually this agreement is done up front between the client application and the back-end service and shared using proper documentation.
  6. Server will hash the string generated in previous step using the same hashing algorithm used by the client (SHA256) and the same API Key obtained from the secure repository for this client.
  7. The result of this hash function (signature) generated at the server will be compared to the signature sent by the client, if they are equal then server will consider this call authentic and process the request, otherwise the server will reject the request and returns HTTP status code 401 unauthorized.

Important note:

  • Client and server should generate the hash (signature) using the same hashing algorithm as well adhere to the same parameters order, any slight change including case sensitivity when implementing the hashing will result in totally different signature and all requests from the client to the server will get rejected. So be consistent and agree on how to generate the signature up front and in clear way.
  • This mechanism of authentication can work without TLS (HTTPS), as long as the client is not transferring any confidential data or transmitting the API Key. It is recommended to consume it over TLS. But if you can’t use TLS for any other reason you will be fine if you transmit data over HTTP.

Sounds complicated? Right? Let’s jump to the implementation to make this clear.

I’ll start by showing how to generate APP Id and strong 265 bits key which will act as our API Key, this usually will be done on the server and provided to the client using a secure mechanism (Secure admin server portal). There is nice post here explains why generating APP Ids and API Keys is more secure than issuing username and password.

Then I’ll build a simple console application which will act as the client application, lastly I’ll build HTTP service using ASP.NET Web API and protected using HMAC Authentication using the right filter “IAuthenticationFilter”, so let’s get started!

The source code for this tutorial is available on GitHub.

Section 1: Generating the Shared Private Key (API Key) and APP Id

As I stated before this should be done on the server and provided to the client prior the actual use, we’ll use symmetric key cryptographic algorithm to issue 256 bit key, the code will be as the below:

using (var cryptoProvider = new RNGCryptoServiceProvider())
	{
		byte[] secretKeyByteArray = new byte[32]; //256 bit
		cryptoProvider.GetBytes(secretKeyByteArray);
		var APIKey = Convert.ToBase64String(secretKeyByteArray);
	}

And for the APP Id you can generate a GUID, so for this tutorial let’s assume that our APPId is:

4d53bce03ec34c0a911182d4c228ee6c
  and our APIKey generated is: 
A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=
 and assume that our client application has received those 2 pieces of information using a secure channel.

Section 2: Building the Client Application

Step 1: Install Nuget Package
Add new empty solution named “WebApiHMACAuthentication” then add new console application named “HMACAuthentication.Client”, then install the below HTTPClient Nuget package which help us to issue HTTP requests.

Install-Package Microsoft.AspNet.WebApi.Client -Version 5.2.2

Step 2: Add POCO Model
We’ll issue HTTP POST request in order to demonstrate how we can include the request body in the signature, so we’ll add simple model named “Order”, add new class named “Order” and paste the code below:

public class Order
    {
        public int OrderID { get; set; }
        public string CustomerName { get; set; }
        public string ShipperCity { get; set; }
        public Boolean IsShipped { get; set; }
    }

Step 3: Call the back-end API using HTTPClient
Now we’ll use the HTTPClient library installed earlier to issue HTTP POST request to the API we’ll build in the next section, so open file “Program.cs” and paste the code below:

static void Main(string[] args)
        {
            RunAsync().Wait();
        }

        static async Task RunAsync()
        {

            Console.WriteLine("Calling the back-end API");

            string apiBaseAddress = "http://localhost:43326/";

            CustomDelegatingHandler customDelegatingHandler = new CustomDelegatingHandler();

            HttpClient client = HttpClientFactory.Create(customDelegatingHandler);

            var order = new Order { OrderID = 10248, CustomerName = "Taiseer Joudeh", ShipperCity = "Amman", IsShipped = true };

            HttpResponseMessage response = await client.PostAsJsonAsync(apiBaseAddress + "api/orders", order);

            if (response.IsSuccessStatusCode)
            {
                string responseString = await response.Content.ReadAsStringAsync();
                Console.WriteLine(responseString);
                Console.WriteLine("HTTP Status: {0}, Reason {1}. Press ENTER to exit", response.StatusCode, response.ReasonPhrase);
            }
            else
            {
                Console.WriteLine("Failed to call the API. HTTP Status: {0}, Reason {1}", response.StatusCode, response.ReasonPhrase);
            }

            Console.ReadLine();
        }

What we implemented here is basic, we just issuing HTTP POST to the end point “/api/orders” including serialized order object, this end point is protected using HMAC Authentication (More about this later in post), and if the response status returned is 200 OK, then we are printing the response returned.

What worth nothing here that I’m using a custom delegation handler named “CustomDelegatingHandler”. This handler will help us to intercept the request before sending it so we can do the signing process and creating the signature there.

Step 4: Implement the HTTPClient Custom Handler
HTTPClient allows us to create custom message handler which get created and added to the request message handlers chain, the nice thing here that this handler will allow us to write out custom logic (logic needed to build the hash and set in the Authorization header before firing the request to the back-end API), so in the same file “Program.cs” add new class named “CustomDelegatingHandler” and paste the code below:

public class CustomDelegatingHandler : DelegatingHandler
        {
            //Obtained from the server earlier, APIKey MUST be stored securely and in App.Config
            private string APPId = "4d53bce03ec34c0a911182d4c228ee6c";
            private string APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";

            protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {

                HttpResponseMessage response = null;
                string requestContentBase64String = string.Empty;

                string requestUri = System.Web.HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower());

                string requestHttpMethod = request.Method.Method;

                //Calculate UNIX time
                DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
                TimeSpan timeSpan = DateTime.UtcNow - epochStart;
                string requestTimeStamp = Convert.ToUInt64(timeSpan.TotalSeconds).ToString();

                //create random nonce for each request
                string nonce = Guid.NewGuid().ToString("N");

                //Checking if the request contains body, usually will be null wiht HTTP GET and DELETE
                if (request.Content != null)
                {
                    byte[] content = await request.Content.ReadAsByteArrayAsync();
                    MD5 md5 = MD5.Create();
                    //Hashing the request body, any change in request body will result in different hash, we'll incure message integrity
                    byte[] requestContentHash = md5.ComputeHash(content);
                    requestContentBase64String = Convert.ToBase64String(requestContentHash);
                }

                //Creating the raw signature string
                string signatureRawData = String.Format("{0}{1}{2}{3}{4}{5}", APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String);

                var secretKeyByteArray = Convert.FromBase64String(APIKey);

                byte[] signature = Encoding.UTF8.GetBytes(signatureRawData);

                using (HMACSHA256 hmac = new HMACSHA256(secretKeyByteArray))
                {
                    byte[] signatureBytes = hmac.ComputeHash(signature);
                    string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
                    //Setting the values in the Authorization header using custom scheme (amx)
                    request.Headers.Authorization = new AuthenticationHeaderValue("amx", string.Format("{0}:{1}:{2}:{3}", APPId, requestSignatureBase64String, nonce, requestTimeStamp));
                }

                response = await base.SendAsync(request, cancellationToken);

                return response;
            }
        }

What we’ve implemented above is the following:

  • We’ve hard coded the APP Id and API Key values obtained earlier from the server, usually you need to store those values securely in app.config.
  • We’ve got the full request URI and safely Url Encoded it, so in case there is query strings sent with the request they will safely encoded, as well we’ve read the HTTP method used, in our case it will be POST.
  • We’ve calculated the time stamp for the request using UNIX timing (number of seconds since Jan. 1st 1970). This will help us to avoid any issues might happen if the client and the server resides in two different time zones.
  • We’ve generated a random nonce for this request, the client should adhere to this and should send a random string per method call.
  • We’ve checked if the request contains a body (it will contain a body if the request of type HTTP POST or PUT), if it contains a body; then we will md5 hash the body content then Base64 the array, we are doing this to insure the authenticity of the request and to make sure no one tampered with the request during the transmission (in case of transmitting it over HTTP).
  • We’ve built the signature raw data by concatenating the parameters (APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String) without any delimiters, this data will get hashed using HMACSHA256 algorithm.
  • Lastly we’ve applied the hashing algorithm using the API Key then base64 the result and combined the (APPId:requestSignatureBase64String:nonce:requestTimeStamp) using ‘:’ colon delimiter and set this combined string in the Authorization header for the request using a custom scheme named “amx”. Notice that the nonce and time stamp are included in creating the request signature as well they are sent as plain text values so they can be validated on the server to protect our API from replay attacks.

We are done of the client part, now let’s move to building the Web API which will be protected using HMAC Authentication.

Section 3: Building the back-end API

Step 1: Add the Web API Project
Add new Web application project named “HMACAuthentication.WebApi” to our existing solution “WebApiHMACAuthentication”, the template for the API will be as the image below (Web API core dependency checked) or you can use OWIN as we did in previous tutorials:

WebApiProject

Step 2: Add Orders Controller
We’ll add simple controller named “Orders” controller with 2 simple HTTP methods, as well we’ll add the same model “Order” we already added in the client application, so add new class named “OrdersController” and paste the code below, nothing special here, just basic Web API controller which is not protected and allows anonymous calls (we’ll protect it later in the post).

[RoutePrefix("api/Orders")]
    public class OrdersController : ApiController
    {
        [Route("")]
        public IHttpActionResult Get()
        {
            ClaimsPrincipal principal = Request.GetRequestContext().Principal as ClaimsPrincipal;

            var Name = ClaimsPrincipal.Current.Identity.Name;

            return Ok(Order.CreateOrders());
        }

        [Route("")]
        public IHttpActionResult Post(Order order)
        {
            return Ok(order);
        }

    }

    #region Helpers

    public class Order
    {
        public int OrderID { get; set; }
        public string CustomerName { get; set; }
        public string ShipperCity { get; set; }
        public Boolean IsShipped { get; set; }


        public static List<Order> CreateOrders()
        {
            List<Order> OrderList = new List<Order> 
            {
                new Order {OrderID = 10248, CustomerName = "Taiseer Joudeh", ShipperCity = "Amman", IsShipped = true },
                new Order {OrderID = 10249, CustomerName = "Ahmad Hasan", ShipperCity = "Dubai", IsShipped = false},
                new Order {OrderID = 10250,CustomerName = "Tamer Yaser", ShipperCity = "Jeddah", IsShipped = false },
                new Order {OrderID = 10251,CustomerName = "Lina Majed", ShipperCity = "Abu Dhabi", IsShipped = false},
                new Order {OrderID = 10252,CustomerName = "Yasmeen Rami", ShipperCity = "Kuwait", IsShipped = true}
            };

            return OrderList;
        }
    }

    #endregion

Step 3: Build the HMAC Authentication Filter
We’ll add all our logic responsible for re-generating the signature on the Web API and comparing it with signature received by the client in an Authentication Filter. The authentication filter is available in Web API 2 and it should be used for any authentication purposes, in our case we will use this filter to write our custom logic which validates the authenticity of the signature received by the client. The nice thing about this filter that it run before any other filters especially the authorization filter, I’ll borrow the image below from a great article about ASP.NET Web API Security Filters by Badrinarayanan Lakshmiraghavan to give you better understanding on where the authentication filter resides.

ASP.NET Web API Security Filters
Now add new folder named “Filters” then add new class named “HMACAuthenticationAttribute” which inherits from “Attribute” and implements interface “IAuthenticationFilter”, then paste the code below:

public class HMACAuthenticationAttribute : Attribute, IAuthenticationFilter
    {
        private static Dictionary<string, string> allowedApps = new Dictionary<string, string>();
        private readonly UInt64 requestMaxAgeInSeconds = 300;  //5 mins
        private readonly string authenticationScheme = "amx";

        public HMACAuthenticationAttribute()
        {
            if (allowedApps.Count == 0)
            {
                allowedApps.Add("4d53bce03ec34c0a911182d4c228ee6c", "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=");
            }
        }

        public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
        {
            var req = context.Request;

            if (req.Headers.Authorization != null && authenticationScheme.Equals(req.Headers.Authorization.Scheme, StringComparison.OrdinalIgnoreCase))
            {
                var rawAuthzHeader = req.Headers.Authorization.Parameter;

                var autherizationHeaderArray = GetAutherizationHeaderValues(rawAuthzHeader);

                if (autherizationHeaderArray != null)
                {
                    var APPId = autherizationHeaderArray[0];
                    var incomingBase64Signature = autherizationHeaderArray[1];
                    var nonce = autherizationHeaderArray[2];
                    var requestTimeStamp = autherizationHeaderArray[3];

                    var isValid = isValidRequest(req, APPId, incomingBase64Signature, nonce, requestTimeStamp);

                    if (isValid.Result)
                    {
                        var currentPrincipal = new GenericPrincipal(new GenericIdentity(APPId), null);
                        context.Principal = currentPrincipal;
                    }
                    else
                    {
                        context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
                    }
                }
                else
                {
                    context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
                }
            }
            else
            {
                context.ErrorResult = new UnauthorizedResult(new AuthenticationHeaderValue[0], context.Request);
            }

            return Task.FromResult(0);
        }

        public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
        {
            context.Result = new ResultWithChallenge(context.Result);
            return Task.FromResult(0);
        }

        public bool AllowMultiple
        {
            get { return false; }
        }

        private string[] GetAutherizationHeaderValues(string rawAuthzHeader)
        {

            var credArray = rawAuthzHeader.Split(':');

            if (credArray.Length == 4)
            {
                return credArray;
            }
            else
            {
                return null;
            }

        }
}

Basically what we’ve implemented is the following:

  • The class “HMACAuthenticationAttribute” derives from “Attribute” class so we can use it as filter attribute over our controllers or HTTP action methods.
  • The constructor for the class currently fill a dictionary named “allowedApps”, this is for the demo only, usually you will store the APP Id and API Key in a database along with other information about this client.
  • The method “AuthenticateAsync” is used to implement the core authentication logic of validating the incoming signature in the request
  • We make sure that the Authorization header is not empty and it contains scheme of type “amx”, then we read the Authorization header value and split its content based on the delimiter we’ve specified earlier in client ‘:’.
  • Lastly we are calling method “isValidRequest” where all the magic of reconstructing the signature and comparing it with the incoming signature happens. More about implementing this in step 5.
  • Incase the Authorization header is incorrect or the result of executing method “isValidRequest” returns false, we’ll consider the incoming request as unauthorized and we should return an authentication challenge to the response, this should be implemented in method “ChallengeAsync”, to do so lets implement the next step.

Step 4: Add authentication challenge to the response
To add authentication challenge to the unauthorized response copy and paste the code below in the same file “HMACAuthenticationAttribute.cs”, basically we’ll add “WWW-Authenticate” header to the response using our “amx” custom scheme . You can read more about the details of this implementation here.

public class ResultWithChallenge : IHttpActionResult
    {
        private readonly string authenticationScheme = "amx";
        private readonly IHttpActionResult next;

        public ResultWithChallenge(IHttpActionResult next)
        {
            this.next = next;
        }

        public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            var response = await next.ExecuteAsync(cancellationToken);

            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(authenticationScheme));
            }

            return response;
        }
    }

Step 5: Implement the method “isValidRequest”.
The core implementation of reconstructing the request parameters and generating the signature on the server happens here, so let’s add the code then I’ll describe what this method is responsible for, open file “HMACAuthenticationAttribute.cs” again and paste the code below in class “HMACAuthenticationAttribute”:

private async Task<bool> isValidRequest(HttpRequestMessage req, string APPId, string incomingBase64Signature, string nonce, string requestTimeStamp)
        {
            string requestContentBase64String = "";
            string requestUri = HttpUtility.UrlEncode(req.RequestUri.AbsoluteUri.ToLower());
            string requestHttpMethod = req.Method.Method;

            if (!allowedApps.ContainsKey(APPId))
            {
                return false;
            }

            var sharedKey = allowedApps[APPId];

            if (isReplayRequest(nonce, requestTimeStamp))
            {
                return false;
            }

            byte[] hash = await ComputeHash(req.Content);

            if (hash != null)
            {
                requestContentBase64String = Convert.ToBase64String(hash);
            }

            string data = String.Format("{0}{1}{2}{3}{4}{5}", APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String);

            var secretKeyBytes = Convert.FromBase64String(sharedKey);

            byte[] signature = Encoding.UTF8.GetBytes(data);

            using (HMACSHA256 hmac = new HMACSHA256(secretKeyBytes))
            {
                byte[] signatureBytes = hmac.ComputeHash(signature);

                return (incomingBase64Signature.Equals(Convert.ToBase64String(signatureBytes), StringComparison.Ordinal));
            }

        }

        private bool isReplayRequest(string nonce, string requestTimeStamp)
        {
            if (System.Runtime.Caching.MemoryCache.Default.Contains(nonce))
            {
                return true;
            }

            DateTime epochStart = new DateTime(1970, 01, 01, 0, 0, 0, 0, DateTimeKind.Utc);
            TimeSpan currentTs = DateTime.UtcNow - epochStart;

            var serverTotalSeconds = Convert.ToUInt64(currentTs.TotalSeconds);
            var requestTotalSeconds = Convert.ToUInt64(requestTimeStamp);

            if ((serverTotalSeconds - requestTotalSeconds) > requestMaxAgeInSeconds)
            {
                return true;
            }

            System.Runtime.Caching.MemoryCache.Default.Add(nonce, requestTimeStamp, DateTimeOffset.UtcNow.AddSeconds(requestMaxAgeInSeconds));

            return false;
        }

        private static async Task<byte[]> ComputeHash(HttpContent httpContent)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] hash = null;
                var content = await httpContent.ReadAsByteArrayAsync();
                if (content.Length != 0)
                {
                    hash = md5.ComputeHash(content);
                }
                return hash;
            }
        }

What we’ve implemented here is the below:

  • We’ve validated that public APPId received is registered in our system, if it is not we’ll return false and will return unauthorized response.
  • We’ve checked if the request received is a replay request, this means that checking if the nonce received by the client is used before, currently I’m storing all the nonce received by the client in Cache Memory for 5 minutes only, so for example if the client generated a nonce “abc1234″ and send it with a request, the server will check if this nonce is used before, if not it will store the nonce for 5 minutes, so any request coming with same nonce during the 5 minutes window will consider a replay attack, if the same nonce “abc1234″ is used after 5 minutes then this is fine and the request is not considered a replay attack.
  • But there might be an evil person that might try to re-post the same request using the same nonce after the 5 minutes window, so the request time stamp becomes handy here, the implementation is comparing the current server UNIX time with the request UNIX time from the client, if the request age is older than 5 minutes too then it is rejected and the the evil person has no possibility to fake the request time stamp and send fresher one because we’ve already included the request time stamp in the signature raw data, so any change on it will result into new signature and it will not match the client incoming signature.
  • Note: If your API is published on different nodes on web farm, then you can store those nonce using Microsoft Azure Cache or Redis server, do not store them in DB because you need fast rad access.
  • Last step is we’ve implemented is to md5 hash the request body content if it is available (POST, PUT methods), then we’ve built the signature raw data by concatenating the parameters (APPId, requestHttpMethod, requestUri, requestTimeStamp, nonce, requestContentBase64String) without any delimiters. It is a MUST that both parties use the same data format to produce the same signature, the data eventually will get hashed using the same hashing algorithm and API Key used by the client. If the incoming client signature equals the signature generated on the server then we’ll consider this request authentic and will process it.

Step 5: Secure the API End Points:
Final thing to do here is to attribute the protected end points or controllers with this new authentication filter attribute, so open controller “Orders” and add the attribute “HMACAuthentication” as the code below:

[HMACAuthentication]
    [RoutePrefix("api/Orders")]
    public class OrdersController : ApiController
    {
     //Controller implementation goes here
    }

 Conclusion:

  • In my opinion HMAC authentication is more complicated than OAuth 2.0 but in some situations you need to use it especially if you can’t use TLS, or when you are building HTTP service that will be consumed by terminals or devices which storing the API Key in it is fine.
  • I’ve read that OAuth 1.0a is very similar to this approach, I’m not an expert of this protocol and I’m not trying to reinvent the wheel, I want to build this without the use of any external library, so for anyone reading this and have experience with OAuth 1.0a please drop me a comment telling the differences/ similarities about this approach and OAuth 1.0a.

That’s all for now folks! Please drop me a comment if you have better way implementing this or you spotted something that could be done in a better way.

The source code for this tutorial is available on GitHub.

Follow me on Twitter @tjoudeh

References:

The post Secure ASP.NET Web API using API Key Authentication – HMAC Authentication appeared first on Bit of Technology.

ASP.NET Identity 2.1 with ASP.NET Web API 2.2 (Accounts Management) – Part 1

$
0
0

Asp Net Identity

ASP.NET Identity 2.1 is the latest membership and identity management framework provided by Microsoft, this membership system can be plugged to any ASP.NET framework such as Web API, MVC, Web Forms, etc…

In this tutorial we’ll cover how to integrate ASP.NET Identity system with ASP.NET Web API , so we can build a secure HTTP service which acts as back-end for SPA front-end built using AngularJS, I’ll try to cover in a simple way different ASP.NET Identity 2.1 features such as: Accounts managements, roles management, email confirmations, change password, roles based authorization, claims based authorization, brute force protection, etc…

The AngularJS front-end application will use bearer token based authentication using Json Web Tokens (JWTs) format and should support roles based authorization and contains the basic features of any membership system. The SPA is not ready yet but hopefully it will sit on top of our HTTP service without the need to come again and modify the ASP.NET Web API logic.

I will follow step by step approach and I’ll start from scratch without using any VS 2013 templates so we’ll have better understanding of how the ASP.NET Identity 2.1 framework talks with ASP.NET Web API framework.

The source code for this tutorial is available on GitHub.

I broke down this series into multiple posts which I’ll be posting gradually, posts are:

  • Configure ASP.NET Identity with ASP.NET Web API (Accounts Management) – (This Post)
  • ASP.NET Identity Accounts Confirmation,  and Token Based Authentication – Part 2
  • ASP.NET Identity Role Based Authorization with ASP.NET Web API – Part 3
  • ASP.NET Identity Authorization Access using Claims with ASP.NET Web API – Part 4
  • AngularJS Authentication and Authorization with ASP.NET Web API and Identity – Part 5

Configure ASP.NET Identity 2.1 with ASP.NET Web API 2.2 (Accounts Management)

Setting up the ASP.NET Identity 2.1

Step 1: Create the Web API Project

In this tutorial I’m using Visual Studio 2013 and .Net framework 4.5, now create an empty solution and name it “AspNetIdentity” then add new ASP.NET Web application named “AspNetIdentity.WebApi”, we will select an empty template with no core dependencies at all, it will be as as the image below:

WebApiNewProject

Step 2: Install the needed NuGet Packages:

We’ll install all those NuGet packages to setup our Owin server and configure ASP.NET Web API to be hosted within an Owin server, as well we will install packages needed for ASP.NET Identity 2.1, if you would like to know more about the use of each package and what is the Owin server, please check this post.

Install-Package Microsoft.AspNet.Identity.Owin -Version 2.1.0
Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.1.0
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0

 Step 3: Add Application user class and Application Database Context:

Now we want to define our first custom entity framework class which is the “ApplicationUser” class, this class will represents a user wants to register in our membership system, as well we want to extend the default class in order to add application specific data properties for the user, data properties such as: First Name, Last Name, Level, JoinDate. Those properties will be converted to columns in table “AspNetUsers” as we’ll see on the next steps.

So to do this we need to create new class named “ApplicationUser” and derive from “Microsoft.AspNet.Identity.EntityFramework.IdentityUser” class.

Note: If you do not want to add any extra properties to this class, then there is no need to extend the default implementation and derive from “IdentityUser” class.

To do so add new folder named “Infrastructure” to our project then add new class named “ApplicationUser” and paste the code below:

public class ApplicationUser : IdentityUser
    {
        [Required]
        [MaxLength(100)]
        public string FirstName { get; set; }

        [Required]
        [MaxLength(100)]
        public string LastName { get; set; }

        [Required]
        public byte Level { get; set; }

        [Required]
        public DateTime JoinDate { get; set; }

    }

Now we need to add Database context class which will be responsible to communicate with our database, so add new class and name it “ApplicationDbContext” under folder “Infrastructure” then paste the code snippet below:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
            Configuration.ProxyCreationEnabled = false;
            Configuration.LazyLoadingEnabled = false;
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

    }

As you can see this class inherits from “IdentityDbContext” class, you can think about this class as special version of the traditional “DbContext” Class, it will provide all of the entity framework code-first mapping and DbSet properties needed to manage the identity tables in SQL Server, this default constructor takes the connection string name “DefaultConnection” as an argument, this connection string will be used point to the right server and database name to connect to.

The static method “Create” will be called from our Owin Startup class, more about this later.

Lastly we need to add a connection string which points to the database that will be created using code first approach, so open “Web.config” file and paste the connection string below:

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=.\sqlexpress;Initial Catalog=AspNetIdentity;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
  </connectionStrings>

Step 4: Create the Database and Enable DB migrations:

Now we want to enable EF code first migration feature which configures the code first to update the database schema instead of dropping and re-creating the database with each change on EF entities, to do so we need to open NuGet Package Manager Console and type the following commands:

enable-migrations
add-migration InitialCreate

The “enable-migrations” command creates a “Migrations” folder in the “AspNetIdentity.WebApi” project, and it creates a file named “Configuration”, this file contains method named “Seed” which is used to allow us to insert or update test/initial data after code first creates or updates the database. This method is called when the database is created for the first time and every time the database schema is updated after a data model change.

Migrations

As well the “add-migration InitialCreate” command generates the code that creates the database from scratch. This code is also in the “Migrations” folder, in the file named “<timestamp>_InitialCreate.cs“. The “Up” method of the “InitialCreate” class creates the database tables that correspond to the data model entity sets, and the “Down” method deletes them. So in our case if you opened this class “201501171041277_InitialCreate” you will see the extended data properties we added in the “ApplicationUser” class in method “Up”.

Now back to the “Seed” method in class “Configuration”, open the class and replace the Seed method code with the code below:

protected override void Seed(AspNetIdentity.WebApi.Infrastructure.ApplicationDbContext context)
        {
            //  This method will be called after migrating to the latest version.

            var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));

            var user = new ApplicationUser()
            {
                UserName = "SuperPowerUser",
                Email = "taiseer.joudeh@mymail.com",
                EmailConfirmed = true,
                FirstName = "Taiseer",
                LastName = "Joudeh",
                Level = 1,
                JoinDate = DateTime.Now.AddYears(-3)
            };

            manager.Create(user, "MySuperP@ssword!");
        }

This code basically creates a user once the database is created.

Now we are ready to trigger the event which will create the database on our SQL server based on the connection string we specified earlier, so open NuGet Package Manager Console and type the command:

update-database

The “update-database” command runs the “Up” method in the “Configuration” file and creates the database and then it runs the “Seed” method to populate the database and insert a user.

If all is fine, navigate to your SQL server instance and the database along with the additional fields in table “AspNetUsers” should be created as the image below:

AspNetIdentityDB

Step 5: Add the User Manager Class:

The User Manager class will be responsible to manage instances of the user class, the class will derive from “UserManager<T>”  where T will represent our “ApplicationUser” class, once it derives from the “ApplicationUser” class a set of methods will be available, those methods will facilitate managing users in our Identity system, some of the exposed methods we’ll use from the “UserManager” during this tutorial are:

Method NameUsage
FindByIdAsync(id)Find user object based on its unique identifier
UsersReturns an enumeration of the users
FindByNameAsync(Username)Find user based on its Username
CreateAsync(User, PasswordCreates a new user with a password
GenerateEmailConfirmationTokenAsync(Id)Generate email confirmation token which is used in email confimration
SendEmailAsync(Id, Subject, Body)Send confirmation email to the newly registered user
ConfirmEmailAsync(Id, token)Confirm the user email based on the received token
ChangePasswordAsync(Id, OldPassword, NewPassword)Change user password
DeleteAsync(User)Delete user
IsInRole(Username, Rolename)Check if a user belongs to certain Role
AddToRoleAsync(Username, RoleName)Assign user to a specific Role
RemoveFromRoleAsync(Username, RoleNameRemove user from specific Role

Now to implement the “UserManager” class, add new file named “ApplicationUserManager” under folder “Infrastructure” and paste the code below:

public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store)
            : base(store)
        {
        }

        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
        {
            var appDbContext = context.Get<ApplicationDbContext>();
            var appUserManager = new ApplicationUserManager(new UserStore<ApplicationUser>(appDbContext));

            return appUserManager;
        }
    }

As you notice from the code above the static method “Create” will be responsible to return an instance of the “ApplicationUserManager” class named “appUserManager”, the constructor of the “ApplicationUserManager” expects to receive an instance from the “UserStore”, as well the UserStore instance construct expects to receive an instance from our “ApplicationDbContext” defined earlier, currently we are reading this instance from the Owin context, but we didn’t add it yet to the Owin context, so let’s jump to the next step to add it.

Note: In the coming post we’ll apply different changes to the “ApplicationUserManager” class such as configuring email service, setting user and password polices.

Step 6: Add Owin “Startup” Class

Now we’ll add the Owin “Startup” class which will be fired once our server starts. The “Configuration” method accepts parameter of type “IAppBuilder” this parameter will be supplied by the host at run-time. This “app” parameter is an interface which will be used to compose the application for our Owin server, so add new file named “Startup” to the root of the project and paste the code below:

public class Startup
    {

        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration httpConfig = new HttpConfiguration();

            ConfigureAuth(app);

            ConfigureWebApi(httpConfig);

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            app.UseWebApi(httpConfig);

        }

        private void ConfigureAuth(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

	    // Plugin the OAuth bearer tokens generation and Consumption will be here

        }

        private void ConfigureWebApi(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        }
    }

What worth noting here is how we are creating a fresh instance from the “ApplicationDbContext” and “ApplicationUserManager” for each request and set it in the Owin context using the extension method “CreatePerOwinContext”. Both objects (ApplicationDbContext and AplicationUserManager) will be available during the entire life of the request.

Note: I didn’t plug any kind of authentication here, we’ll visit this class again and add JWT Authentication in the next post, for now we’ll be fine accepting any request from any anonymous users.

Define Web API Controllers and Methods

Step 7: Create the “Accounts” Controller:

Now we’ll add our first controller named “AccountsController” which will be responsible to manage user accounts in our Identity system, to do so add new folder named “Controllers” then add new class named “AccountsController” and paste the code below:

[RoutePrefix("api/accounts")]
public class AccountsController : BaseApiController
{

	[Route("users")]
	public IHttpActionResult GetUsers()
	{
		return Ok(this.AppUserManager.Users.ToList().Select(u => this.TheModelFactory.Create(u)));
	}

	[Route("user/{id:guid}", Name = "GetUserById")]
	public async Task<IHttpActionResult> GetUser(string Id)
	{
		var user = await this.AppUserManager.FindByIdAsync(Id);

		if (user != null)
		{
			return Ok(this.TheModelFactory.Create(user));
		}

		return NotFound();

	}

	[Route("user/{username}")]
	public async Task<IHttpActionResult> GetUserByName(string username)
	{
		var user = await this.AppUserManager.FindByNameAsync(username);

		if (user != null)
		{
			return Ok(this.TheModelFactory.Create(user));
		}

		return NotFound();

	}
}

What we have implemented above is the following:

  • Our “AccountsController” inherits from base controller named “BaseApiController”, this base controller is not created yet, but it contains methods that will be reused among different controllers we’ll add during this tutorial, the methods which comes from “BaseApiController” are: “AppUserManager”, “TheModelFactory”, and “GetErrorResult”, we’ll see the implementation for this class in the next step.
  • We have added 3 methods/actions so far in the “AccountsController”:
    • Method “GetUsers” will be responsible to return all the registered users in our system by calling the enumeration “Users” coming from “ApplicationUserManager” class.
    • Method “GetUser” will be responsible to return single user by providing it is unique identifier and calling the method “FindByIdAsync” coming from “ApplicationUserManager” class.
    • Method “GetUserByName” will be responsible to return single user by providing it is username and calling the method “FindByNameAsync” coming from “ApplicationUserManager” class.
    • The three methods send the user object to class named “TheModelFactory”, we’ll see in the next step the benefit of using this pattern to shape the object graph returned and how it will protect us from leaking any sensitive information about the user identity.
  • Note: All methods can be accessed by any anonymous user, for now we are fine with this, but we’ll manage the access control for each method and who are the authorized identities that can perform those actions in the coming posts.

Step 8: Create the “BaseApiController” Controller:

As we stated before, this “BaseApiController” will act as a base class which other Web API controllers will inherit from, for now it will contain three basic methods, so add new class named “BaseApiController” under folder “Controllers” and paste the code below:

public class BaseApiController : ApiController
    {

        private ModelFactory _modelFactory;
        private ApplicationUserManager _AppUserManager = null;

        protected ApplicationUserManager AppUserManager
        {
            get
            {
                return _AppUserManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
        }

        public BaseApiController()
        {
        }

        protected ModelFactory TheModelFactory
        {
            get
            {
                if (_modelFactory == null)
                {
                    _modelFactory = new ModelFactory(this.Request, this.AppUserManager);
                }
                return _modelFactory;
            }
        }

        protected IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (!result.Succeeded)
            {
                if (result.Errors != null)
                {
                    foreach (string error in result.Errors)
                    {
                        ModelState.AddModelError("", error);
                    }
                }

                if (ModelState.IsValid)
                {
                    // No ModelState errors are available to send, so just return an empty BadRequest.
                    return BadRequest();
                }

                return BadRequest(ModelState);
            }

            return null;
        }
    }

What we have implemented above is the following:

  • We have added read only property named “AppUserManager” which gets the instance of the “ApplicationUserManager” we already set in the “Startup” class, this instance will be initialized and ready to invoked.
  • We have added another read only property named “TheModelFactory” which returns an instance of “ModelFactory” class, this factory pattern will help us in shaping and controlling the response returned to the client, so we will create a simplified model for some of our domain object model (Users, Roles, Claims, etc..) we have in the database. Shaping the response and building customized object graph is very important here; because we do not want to leak sensitive data such as “PasswordHash” to the client.
  • We have added a function named “GetErrorResult” which takes “IdentityResult” as a constructor and formats the error messages returned to the client.

Step 8: Create the “ModelFactory” Class:

Now add new folder named “Models” and inside this folder create new class named “ModelFactory”, this class will contain all the functions needed to shape the response object and control the object graph returned to the client, so open the file and paste the code below:

public class ModelFactory
    {
        private UrlHelper _UrlHelper;
        private ApplicationUserManager _AppUserManager;

        public ModelFactory(HttpRequestMessage request, ApplicationUserManager appUserManager)
        {
            _UrlHelper = new UrlHelper(request);
            _AppUserManager = appUserManager;
        }

        public UserReturnModel Create(ApplicationUser appUser)
        {
            return new UserReturnModel
            {
                Url = _UrlHelper.Link("GetUserById", new { id = appUser.Id }),
                Id = appUser.Id,
                UserName = appUser.UserName,
                FullName = string.Format("{0} {1}", appUser.FirstName, appUser.LastName),
                Email = appUser.Email,
                EmailConfirmed = appUser.EmailConfirmed,
                Level = appUser.Level,
                JoinDate = appUser.JoinDate,
                Roles = _AppUserManager.GetRolesAsync(appUser.Id).Result,
                Claims = _AppUserManager.GetClaimsAsync(appUser.Id).Result
            };
        }
    }

    public class UserReturnModel
    {
        public string Url { get; set; }
        public string Id { get; set; }
        public string UserName { get; set; }
        public string FullName { get; set; }
        public string Email { get; set; }
        public bool EmailConfirmed { get; set; }
        public int Level { get; set; }
        public DateTime JoinDate { get; set; }
        public IList<string> Roles { get; set; }
        public IList<System.Security.Claims.Claim> Claims { get; set; }
    }

Notice how we included only the properties needed to return them in users object graph, for example there is no need to return the “PasswordHash” property so we didn’t include it.

Step 9: Add Method to Create Users in”AccountsController”:

It is time to add the method which allow us to register/create users in our Identity system, but before adding it, we need to add the request model object which contains the user data which will be sent from the client, so add new file named “AccountBindingModels” under folder “Models” and paste the code below:

public class CreateUserBindingModel
    {
        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [Display(Name = "Username")]
        public string Username { get; set; }

        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Role Name")]
        public string RoleName { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

The class is very simple, it contains properties for the fields we want to send from the client to our API with some data annotation attributes which help us to validate the model before submitting it to the database, notice how we added property named “RoleName” which will not be used now, but it will be useful in the coming posts.

Now it is time to add the method which register/creates a user, open the controller named “AccountsController” and add new method named “CreateUser” and paste the code below:

[Route("create")]
public async Task<IHttpActionResult> CreateUser(CreateUserBindingModel createUserModel)
{
	if (!ModelState.IsValid)
	{
		return BadRequest(ModelState);
	}

	var user = new ApplicationUser()
	{
		UserName = createUserModel.Username,
		Email = createUserModel.Email,
		FirstName = createUserModel.FirstName,
		LastName = createUserModel.LastName,
		Level = 3,
		JoinDate = DateTime.Now.Date,
	};

	IdentityResult addUserResult = await this.AppUserManager.CreateAsync(user, createUserModel.Password);

	if (!addUserResult.Succeeded)
	{
		return GetErrorResult(addUserResult);
	}

	Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));

	return Created(locationHeader, TheModelFactory.Create(user));
}

What we have implemented here is the following:

  • We validated the request model based on the data annotations we introduced in class “AccountBindingModels”, if there is a field missing then the response will return HTTP 400 with proper error message.
  • If the model is valid, we will use it to create new instance of class “ApplicationUser”, by default we’ll put all the users in level 3.
  • Then we call method “CreateAsync” in the “AppUserManager” which will do the heavy lifting for us, inside this method it will validate if the username, email is used before, and if the password matches our policy, etc.. if the request is valid then it will create new user and add to the “AspNetUsers” table and return success result. From this result and as good practice we should return the resource created in the location header and return 201 created status.

Notes:

  • Sending a confirmation email for the user, and configuring user and password policy will be covered in the next post.
  • As stated earlier, there is no authentication or authorization applied yet, any anonymous user can invoke any available method, but we will cover this authentication and authorization part in the coming posts.

Step 10: Test Methods in”AccountsController”:

Lastly it is time to test the methods added to the API, so fire your favorite REST client Fiddler or PostMan, in my case I prefer PostMan. So lets start testing the “Create” user method, so we need to issue HTTP Post to the URI: “http://localhost:59822/api/accounts/create” as the request below, if creating a user went good you will receive 201 response:

Create User

Now to test the method “GetUsers” all you need to do is to issue HTTP GET to the URI: “http://localhost:59822/api/accounts/users” and the response graph will be as the below:

[
  {
    "url": "http://localhost:59822/api/accounts/user/29e21f3d-08e0-49b5-b523-3d68cf623fd5",
    "id": "29e21f3d-08e0-49b5-b523-3d68cf623fd5",
    "userName": "SuperPowerUser",
    "fullName": "Taiseer Joudeh",
    "email": "taiseer.joudeh@gmail.com",
    "emailConfirmed": true,
    "level": 1,
    "joinDate": "2012-01-17T12:41:40.457",
    "roles": [
      "Admin",
      "Users",
      "SuperAdmin"
    ],
    "claims": [
      {
        "issuer": "LOCAL AUTHORITY",
        "originalIssuer": "LOCAL AUTHORITY",
        "properties": {},
        "subject": null,
        "type": "Phone",
        "value": "123456782",
        "valueType": "http://www.w3.org/2001/XMLSchema#string"
      },
      {
        "issuer": "LOCAL AUTHORITY",
        "originalIssuer": "LOCAL AUTHORITY",
        "properties": {},
        "subject": null,
        "type": "Gender",
        "value": "Male",
        "valueType": "http://www.w3.org/2001/XMLSchema#string"
      }
    ]
  },
  {
    "url": "http://localhost:59822/api/accounts/user/f0f8d481-e24c-413a-bf84-a202780f8e50",
    "id": "f0f8d481-e24c-413a-bf84-a202780f8e50",
    "userName": "tayseer.Joudeh",
    "fullName": "Tayseer Joudeh",
    "email": "tayseer_joudeh@hotmail.com",
    "emailConfirmed": true,
    "level": 3,
    "joinDate": "2015-01-17T00:00:00",
    "roles": [],
    "claims": []
  }
]

The source code for this tutorial is available on GitHub.

In the next post we’ll see how we’ll configure our Identity service to start sending email confirmations, customize username and password polices, implement Json Web Token (JWTs) Authentication and manage the access for the methods.

Follow me on Twitter @tjoudeh

References

The post ASP.NET Identity 2.1 with ASP.NET Web API 2.2 (Accounts Management) – Part 1 appeared first on Bit of Technology.

ASP.NET Identity 2.1 Accounts Confirmation, and Password Policy Configuration – Part 2

$
0
0

This is the second part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:

  • Configure ASP.NET Identity with ASP.NET Web API (Accounts Management) – Part 1.
  • ASP.NET Identity 2.1 Accounts Confirmation, and Password/User Policy Configuration – (This Post)
  • Implement JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – Part 3
  • ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4
  • ASP.NET Identity 2.1 Authorization Access using Claims with ASP.NET Web API – Part 5
  • AngularJS Authentication and Authorization with ASP.NET Web API and Identity 2.1 – Part 6

The source code for this tutorial is available on GitHub.

ASP.NET Identity 2.1 Accounts Confirmation, and Password/User Policy Configuration

In this post we’ll complete on top of what we’ve already built, and we’ll cover the below topics:

  • Send Confirmation Emails after Account Creation.
  • Configure User (Username, Email) and Password policy.
  • Enable Changing Password and Deleting Account.

1 . Send Confirmation Emails after Account Creation

FeaturedImage

ASP.NET Identity 2.1 users table (AspNetUsers) comes by default with a Boolean column named “EmailConfirmed”, this column is used to flag if the email provided by the registered user is valid and belongs to this user in other words that user can access the email provided and he is not impersonating another identity. So our membership system should not allow users without valid email address to log into the system.

The scenario we want to implement that user will register in the system, then a confirmation email will be sent to the email provided upon the registration, this email will include an activation link and a token (code) which is tied to this user only and valid for certain period.

Once the user opens this email and clicks on the activation link, and if the token (code) is valid the field “EmailConfirmed” will be set to “true” and this proves that the email belongs to the registered user.

To do so we need to add a service which is responsible to send emails to users, in my case I’ll use Send Grid which is service provider for sending emails, but you can use any other service provider or your exchange change server to do this. If you want to follow along with this tutorial you can create a free account with Send Grid which provides you with 400 email per day, pretty good!

1.1 Install Send Grid

Now open Package Manager Console and type the below to install Send Grid package, this is not required step if you want to use another email service provider. This packages contains Send Grid APIs which makes sending emails very easy:

install-package Sendgrid

1.2 Add Email Service

Now add new folder named “Services” then add new class named “EmailService” and paste the code below:

public class EmailService : IIdentityMessageService
    {
        public async Task SendAsync(IdentityMessage message)
        {
            await configSendGridasync(message);
        }

        // Use NuGet to install SendGrid (Basic C# client lib) 
        private async Task configSendGridasync(IdentityMessage message)
        {
            var myMessage = new SendGridMessage();

            myMessage.AddTo(message.Destination);
            myMessage.From = new System.Net.Mail.MailAddress("taiseer@bitoftech.net", "Taiseer Joudeh");
            myMessage.Subject = message.Subject;
            myMessage.Text = message.Body;
            myMessage.Html = message.Body;

            var credentials = new NetworkCredential(ConfigurationManager.AppSettings["emailService:Account"], 
                                                    ConfigurationManager.AppSettings["emailService:Password"]);

            // Create a Web transport for sending email.
            var transportWeb = new Web(credentials);

            // Send the email.
            if (transportWeb != null)
            {
                await transportWeb.DeliverAsync(myMessage);
            }
            else
            {
                //Trace.TraceError("Failed to create Web transport.");
                await Task.FromResult(0);
            }
        }
    }

What worth noting here that the class “EmailService” implements the interface “IIdentityMessageService”, this interface can be used to configure your service to send emails or SMS messages, all you need to do is to implement your email or SMS Service in method “SendAsync” and your are good to go.

In our case we want to send emails, so I’ve implemented the sending process using Send Grid in method “configSendGridasync”, all you need to do is to replace the sender name and address by yours, as well do not forget to add 2 new keys named “emailService:Account” and “emailService:Password” as AppSettings to store Send Grid credentials.

After we configured the “EmailService”, we need to hock it with our Identity system, and this is very simple step, open file “ApplicationUserManager” and inside method “Create” paste the code below:

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
	//Rest of code is removed for clarity
	appUserManager.EmailService = new AspNetIdentity.WebApi.Services.EmailService();

	var dataProtectionProvider = options.DataProtectionProvider;
	if (dataProtectionProvider != null)
	{
		appUserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
		{
			//Code for email confirmation and reset password life time
			TokenLifespan = TimeSpan.FromHours(6)
		};
	}
   
	return appUserManager;
}

As you see from the code above, the “appUserManager” instance contains property named “EmailService” which you set it the class we’ve just created “EmailService”.

Note: There is another property named “SmsService” if you would like to use it for sending SMS messages instead of emails.

Notice how we are setting the expiration time for the code (token) send by the email to 6 hours, so if the user tried to open the confirmation email after 6 hours from receiving it, the code will be invalid.

1.3 Send the Email after Account Creation

Now the email service is ready and we can start sending emails after successful account creation, to do so we need to modify the existing code in the method “CreateUser” in controller “AccountsController“, so open file “AccountsController” and paste the code below at the end of the method:

//Rest of code is removed for brevity

string code = await this.AppUserManager.GenerateEmailConfirmationTokenAsync(user.Id);

var callbackUrl = new Uri(Url.Link("ConfirmEmailRoute", new { userId = user.Id, code = code }));

await this.AppUserManager.SendEmailAsync(user.Id,"Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

Uri locationHeader = new Uri(Url.Link("GetUserById", new { id = user.Id }));

return Created(locationHeader, TheModelFactory.Create(user));

The implementation is straight forward, what we’ve done here is creating a unique code (token) which is valid for the next 6 hours and tied to this user Id only this happen when calling “GenerateEmailConfirmationTokenAsync” method, then we want to build an activation link to send it in the email body, this link will contain the user Id and the code created.

Eventually this link will be sent to the registered user to the email he used in registration, and the user needs to click on it to activate the account, the route “ConfirmEmailRoute” which maps to this activation link is not implemented yet, we’ll implement it the next step.

Lastly we need to send the email including the link we’ve built by calling the method “SendEmailAsync” where the constructor accepts the user Id, email subject, and email body.

1.4 Add the Confirm Email URL

The activation link which the user will receive will look as the below:

http://localhost/api/account/ConfirmEmail?userid=xxxx&code=xxxx

So we need to build a route in our API which receives this request when the user clicks on the activation link and issue HTTP GET request, to do so we need to implement the below method, so in class “AccountsController” as the new method as the below:

[HttpGet]
        [Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
        public async Task<IHttpActionResult> ConfirmEmail(string userId = "", string code = "")
        {
            if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(code))
            {
                ModelState.AddModelError("", "User Id and Code are required");
                return BadRequest(ModelState);
            }

            IdentityResult result = await this.AppUserManager.ConfirmEmailAsync(userId, code);

            if (result.Succeeded)
            {
                return Ok();
            }
            else
            {
                return GetErrorResult(result);
            }
        }

The implementation is simple, we only validate that the user Id and code is not not empty, then we depend on the method “ConfirmEmailAsync” to do the validation for the user Id and the code, so if the user Id is not tied to this code then it will fail, if the code is expired then it will fail too, if all is good this method will update the database field “EmailConfirmed” in table “AspNetUsers” and set it to “True”, and you are done, you have implemented email account activation!

Important Note: It is recommenced to validate the password before confirming the email account, in some cases the user might miss type the email during the registration, so you do not want end sending the confirmation email for someone else and he receives this email and activate the account on your behalf, so better way is to ask for the account password before activating it, if you want to do this you need to change the “ConfirmEmail” method to POST and send the Password along with user Id and code in the request body, you have the idea so you can implement it by yourself :)

2. Configure User (Username, Email) and Password policy

2.1 Change User Policy

In some cases you want to enforce certain rules on the username and password when users register into your system, so ASP.NET Identity 2.1 system offers this feature, for example if we want to enforce that our username only allows alphanumeric characters and the email associated with this user is unique then all we need to do is to set those properties in class “ApplicationUserManager”, to do so open file “ApplicationUserManager” and paste the code below inside method “Create”:

//Rest of code is removed for brevity
//Configure validation logic for usernames
appUserManager.UserValidator = new UserValidator<ApplicationUser>(appUserManager)
{
	AllowOnlyAlphanumericUserNames = true,
	RequireUniqueEmail = true
};

2.2 Change Password Policy

The same applies for the password policy, for example you can enforce that the password policy must match (minimum 6 characters, requires special character, requires at least one lower case and at least one upper case character), so to implement this policy all we need to do is to set those properties in the same class “ApplicationUserManager” inside method “Create” as the code below:

//Rest of code is removed for brevity
//Configure validation logic for passwords
appUserManager.PasswordValidator = new PasswordValidator
{
	RequiredLength = 6,
	RequireNonLetterOrDigit = true,
	RequireDigit = false,
	RequireLowercase = true,
	RequireUppercase = true,
};

2.3 Implement Custom Policy for User Email and Password

In some scenarios you want to apply your own custom policy for validating email, or password. This can be done easily by creating your own validation classes and hock it to “UserValidator” and “PasswordValidator” properties in class “ApplicationUserManager”.

For example if we want to enforce using only the following domains (“outlook.com”, “hotmail.com”, “gmail.com”, “yahoo.com”) when the user self registers then we need to create a class and derive it from “UserValidator<ApplicationUser>” class, to do so add new folder named “Validators” then add new class named “MyCustomUserValidator” and paste the code below:

public class MyCustomUserValidator : UserValidator<ApplicationUser>
    {

        List<string> _allowedEmailDomains = new List<string> { "outlook.com", "hotmail.com", "gmail.com", "yahoo.com" };

        public MyCustomUserValidator(ApplicationUserManager appUserManager)
            : base(appUserManager)
        {
        }

        public override async Task<IdentityResult> ValidateAsync(ApplicationUser user)
        {
            IdentityResult result = await base.ValidateAsync(user);

            var emailDomain = user.Email.Split('@')[1];

            if (!_allowedEmailDomains.Contains(emailDomain.ToLower()))
            {
                var errors = result.Errors.ToList();

                errors.Add(String.Format("Email domain '{0}' is not allowed", emailDomain));

                result = new IdentityResult(errors);
            }

            return result;
        }
    }

What we have implemented above that the default validation will take place then this custom validation in method “ValidateAsync” will be applied, if there is validation errors it will be added to the existing “Errors” list and returned in the response.

In order to fire this custom validation, we need to open class “ApplicationUserManager” again and hock this custom class to the property “UserValidator” as the code below:

//Rest of code is removed for brevity
//Configure validation logic for usernames
appUserManager.UserValidator = new MyCustomUserValidator(appUserManager)
{
	AllowOnlyAlphanumericUserNames = true,
	RequireUniqueEmail = true
};

Note: The tutorial code is not using the custom “MyCustomUserValidator” class, it exists in the source code for your reference.

Now the same applies for adding custom password policy, all you need to do is to create class named “MyCustomPasswordValidator” and derive it from class “PasswordValidator”, then you override the method “ValidateAsync” implementation as below, so add new file named “MyCustomPasswordValidator” in folder “Validators” and use the code below:

public class MyCustomPasswordValidator : PasswordValidator
    {
        public override async Task<IdentityResult> ValidateAsync(string password)
        {
            IdentityResult result = await base.ValidateAsync(password);

            if (password.Contains("abcdef") || password.Contains("123456"))
            {
                var errors = result.Errors.ToList();
                errors.Add("Password can not contain sequence of chars");
                result = new IdentityResult(errors);
            }
            return result;
        }
    }

In this implementation we added some basic rule which checks if the password contains sequence of characters and reject this type of password by adding this validation result to the Errors list, it is exactly the same as the custom users policy.

Now to attach this class as the default password validator, all you need to do is to open class “ApplicationUserManager” and use the code below:

//Rest of code is removed for brevity
// Configure validation logic for passwords
appUserManager.PasswordValidator = new MyCustomPasswordValidator
{
	RequiredLength = 6,
	RequireNonLetterOrDigit = true,
	RequireDigit = false,
	RequireLowercase = true,
	RequireUppercase = true,
};

All other validation rules will take place (i.e checking minimum password length, checking for special characters) then it will apply the implementation in our “MyCustomPasswordValidator”.

3. Enable Changing Password and Deleting Account

Now we need to add other endpoints which allow the user to change the password, and allow a user in “Admin” role to delete other users account, but those end points should be accessed only if the user is authenticated, we need to know the identity of the user doing this action and in which role(s) the user belongs to. Until now all our endpoints are called anonymously, so lets add those endpoints and we’ll cover the authentication and authorization part next.

3.1 Add Change Password Endpoint

This is easy to implement, all you need to do is to open controller “AccountsController” and paste the code below:

[Route("ChangePassword")]
        public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result = await this.AppUserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

Notice how we are calling the method “ChangePasswordAsync” and passing the authenticated User Id, old password and new password. If you tried to call this endpoint, the extension method “GetUserId” will not work because you are calling it as anonymous user and the system doesn’t know your identity, so hold on the testing until we implement authentication part.

The method “ChangePasswordAsync” will take care of validating your current password, as well validating your new password policy, and then updating your old password with new one.

Do not forget to add the “ChangePasswordBindingModel” to the class “AccountBindingModels” as the code below:

public class ChangePasswordBindingModel
    {
        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Current password")]
        public string OldPassword { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "New password")]
        public string NewPassword { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Confirm new password")]
        [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    
    }

3.2 Delete User Account

We want to add the feature which allows a user in “Admin” role to delete user account, until now we didn’t introduce Roles management or authorization, so we’ll add this end point now and later we’ll do slight modification on it, for now any anonymous user can invoke it and delete any user by passing the user Id.

To implement this we need add new method named “DeleteUser” to the “AccountsController” as the code below:

[Route("user/{id:guid}")]
        public async Task<IHttpActionResult> DeleteUser(string id)
        {

            //Only SuperAdmin or Admin can delete users (Later when implement roles)

            var appUser = await this.AppUserManager.FindByIdAsync(id);

            if (appUser != null)
            {
                IdentityResult result = await this.AppUserManager.DeleteAsync(appUser);

                if (!result.Succeeded)
                {
                    return GetErrorResult(result);
                }

                return Ok();

            }

            return NotFound();
          
        }

This method will check the existence of the user id and based on this it will delete the user. To test this method we need to issue HTTP DELETE request to the end point “api/accounts/user/{id}”.

The source code for this tutorial is available on GitHub.

In the next post we’ll see how we’ll implement Json Web Token (JWTs) Authentication and manage access for all the methods we added until now.

Follow me on Twitter @tjoudeh

References

The post ASP.NET Identity 2.1 Accounts Confirmation, and Password Policy Configuration – Part 2 appeared first on Bit of Technology.

Implement OAuth JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – Part 3

$
0
0

This is the third part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:

The source code for this tutorial is available on GitHub.

Implement JSON Web Tokens Authentication in ASP.NET Web API and and Identity 2.1

Featured Image

Currently our API doesn’t support authentication and authorization, all the requests we receive to any end point are done anonymously, In this post we’ll configure our API which will act as our Authorization Server and Resource Server on the same time to issue JSON Web Tokens for authenticated users and those users will present this JWT to the protected end points in order to access it and process the request.

I will use step by step approach as usual to implement this, but I highly recommend you to read the post JSON Web Token in ASP.NET Web API 2 before completing this one; where I cover deeply what is JSON Web Tokens, the benefits of using JWT over default access tokens, and how they can be used to decouple Authorization server from Resource server. In this tutorial and for the sake of keeping it simple; both OAuth 2.0 roles (Authorization Server and Recourse Server) will live in the same API.

Step 1: Implement OAuth 2.0 Resource Owner Password Credential Flow

We are going to build an API which will be consumed by a trusted client (AngularJS front-end) so we only interested in implementing a single OAuth 2.0 flow where the registered user will present username and password to a specific end point, and the API will validate those credentials, and if all is valid it will return a JWT for the user where the client application used by the user should store it securely and locally in order to present this JWT with each request to any protected end point.

The nice thing about this JWT that it is a self contained token which contains all user claims and roles inside it, so there is no need to do any extra DB queries to fetch those values for the authenticated user. This JWT token will be configured to expire after 1 day of its issue date, so the user is requested to provide credentials again in order to obtain new JWT token.

If you are interested to know how to implement sliding expiration tokens and how you can keep the user logged in; I recommend you to read my other post Enable OAuth Refresh Tokens in AngularJS App which covers this deeply, but adds more complexity to the solution. To keep this tutorial simple we’ll not add refresh tokens here but you can refer to the post and implement it.

To implement the Resource Owner Password Credential flow; we need to add new folder named “Providers” then add a new class named “CustomOAuthProvider”, after you add then paste the code below:

public class CustomOAuthProvider : OAuthAuthorizationServerProvider
    {

        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
            return Task.FromResult<object>(null);
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {

            var allowedOrigin = "*";

            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });

            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

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

            if (!user.EmailConfirmed)
            {
                context.SetError("invalid_grant", "User did not confirm email.");
                return;
            }

            ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
        
            var ticket = new AuthenticationTicket(oAuthIdentity, null);
            
            context.Validated(ticket);
           
        }
    }

This class inherits from class “OAuthAuthorizationServerProvider” and overrides the below two methods:

  • As you notice the “ValidateClientAuthentication” is empty, we are considering the request valid always, because in our implementation our client (AngularJS front-end) is trusted client and we do not need to validate it.
  • The method “GrantResourceOwnerCredentials” is responsible for receiving the username and password from the request and validate them against our ASP.NET 2.1 Identity system, if the credentials are valid and the email is confirmed we are building an identity for the logged in user, this identity will contain all the roles and claims for the authenticated user, until now we didn’t cover roles and claims part of the tutorial, but for the mean time you can consider all users registered in our system without any roles or claims mapped to them.
  • The method “GenerateUserIdentityAsync” is not implemented yet, we’ll add this helper method in the next step. This method will be responsible to fetch the authenticated user identity from the database and returns an object of type “ClaimsIdentity”.
  • Lastly we are creating an Authentication ticket which contains the identity for the authenticated user,  and when we call “context.Validated(ticket)” this will transfer this identity to an OAuth 2.0 bearer access token.

Step 2: Add method “GenerateUserIdentityAsync” to “ApplicationUser” class

Now we’ll add the helper method which will be responsible to get the authenticated user identity (all roles and claims mapped to the user). The “UserManager” class contains a method named “CreateIdentityAsync” to do this task, it will basically query the DB and get all the roles and claims for this user, to implement this open class “ApplicationUser” and paste the code below:

//Rest of code is removed for brevity
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
	var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
	// Add custom user claims here
	return userIdentity;
}

Step 3: Issue JSON Web Tokens instead of Default Access Tokens

Now we want to configure our API to issue JWT tokens instead of default access tokens, to understand what is JWT and why it is better to use it, you can refer back to this post.

First thing we need to installed 2 NueGet packages as the below:

Install-package System.IdentityModel.Tokens.Jwt -Version 4.0.1
Install-package Thinktecture.IdentityModel.Core -Version 1.3.0

There is no direct support for issuing JWT in ASP.NET Web API,  so in order to start issuing JWTs we need to implement this manually by implementing the interface “ISecureDataFormat” and implement the method “Protect”.

To implement this add new file named “CustomJwtFormat” under folder “Providers” and paste the code below:

public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
    {
    
        private readonly string _issuer = string.Empty;

        public CustomJwtFormat(string issuer)
        {
            _issuer = issuer;
        }

        public string Protect(AuthenticationTicket data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];

            string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];

            var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);

            var signingKey = new HmacSigningCredentials(keyByteArray);

            var issued = data.Properties.IssuedUtc;
            
            var expires = data.Properties.ExpiresUtc;

            var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);

            var handler = new JwtSecurityTokenHandler();

            var jwt = handler.WriteToken(token);

            return jwt;
        }

        public AuthenticationTicket Unprotect(string protectedText)
        {
            throw new NotImplementedException();
        }
    }

What we’ve implemented in this class is the following:

  • The class “CustomJwtFormat” implements the interface “ISecureDataFormat<AuthenticationTicket>”, the JWT generation will take place inside method “Protect”.
  • The constructor of this class accepts the “Issuer” of this JWT which will be our API. This API acts as Authorization and Resource Server on the same time, this can be string or URI, in our case we’ll fix it to URI.
  • Inside “Protect” method we are doing the following:
    • As we stated before, this API serves as Resource and Authorization Server at the same time, so we are fixing the Audience Id and Audience Secret (Resource Server) in web.config file, this Audience Id and Secret will be used for HMAC265 and hash the JWT token, I’ve used this implementation to generate the Audience Id and Secret.
    • Do not forget to add 2 new keys “as:AudienceId” and “as:AudienceSecret” to the web.config AppSettings section.
    • Then we prepare the raw data for the JSON Web Token which will be issued to the requester by providing the issuer, audience, user claims, issue date, expiry date, and the signing key which will sign (hash) the JWT payload.
    • Lastly we serialize the JSON Web Token to a string and return it to the requester.
  • By doing this, the requester for an OAuth 2.0 access token from our API will receive a signed token which contains claims for an authenticated Resource Owner (User) and this access token is intended to certain (Audience) as well.

Step 4: Add Support for OAuth 2.0 JWT Generation

Till this moment we didn’t configure our API to use OAuth 2.0 Authentication workflow, to do so open class “Startup” and add new method named “ConfigureOAuthTokenGeneration” as the below:

private void ConfigureOAuthTokenGeneration(IAppBuilder app)
        {
            // Configure the db context and user manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                //For Dev enviroment only (on production should be AllowInsecureHttp = false)
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/oauth/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new CustomOAuthProvider(),
                AccessTokenFormat = new CustomJwtFormat("http://localhost:59822")
            };

            // OAuth 2.0 Bearer Access Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
        }

What we’ve implemented here is the following:

  • The path for generating JWT will be as :”http://localhost:59822/oauth/token”.
  • We’ve specified the expiry for token to be 1 day.
  • We’ve specified the implementation on how to validate the Resource owner user credential in a custom class named “CustomOAuthProvider”.
  • We’ve specified the implementation on how to generate the access token using JWT formats, this custom class named “CustomJwtFormat” will be responsible for generating JWT instead of default access token using DPAPI, note that both format will use Bearer scheme.

Do not forget to call the new method “ConfigureOAuthTokenGeneration” in the Startup “Configuration” as the class below:

public void Configuration(IAppBuilder app)
{
	HttpConfiguration httpConfig = new HttpConfiguration();

	ConfigureOAuthTokenGeneration(app);

	//Rest of code is removed for brevity

}

Our API currently is ready to start issuing JWT access token, so test this out we can issue HTTP POST request as the image below, and we should receive a valid JWT token for the next 24 hours and accepted only by our API.

JSON Web Token

Step 5: Protect the existing end points with [Authorize] Attribute

Now we’ll visit all the end points we have created earlier in previous posts in the “AccountsController” class, and attribute the end points which need to be protected (only authentication user with valid JWT access token can access it) with the [Authorize] attribute as the below:

 – GetUsers, GetUser, GetUserByName, and DeleteUser end points should be accessed by users enrolled in Role “Admin”. Roles Authorization is not implemented yet and for now we will only allow any authentication user to access it, the code change will be as simple as the below:

[Authorize]
[Route("users")]
public IHttpActionResult GetUsers()
{}

[Authorize]
[Route("user/{id:guid}", Name = "GetUserById")]
public async Task<IHttpActionResult> GetUser(string Id)
{}


[Authorize]
[Route("user/{username}")]
public async Task<IHttpActionResult> GetUserByName(string username)
{
}

[Authorize]
[Route("user/{id:guid}")]
public async Task<IHttpActionResult> DeleteUser(string id)
{
}

- CreateUser and ConfirmEmail endpoints should be accessed anonymously always, so we need to attribute it with [AllowAnonymous] as the below:

[AllowAnonymous]
[Route("create")]
public async Task<IHttpActionResult> CreateUser(CreateUserBindingModel createUserModel)
{
}

[AllowAnonymous]
[HttpGet]
[Route("ConfirmEmail", Name = "ConfirmEmailRoute")]
public async Task<IHttpActionResult> ConfirmEmail(string userId = "", string code = "")
{
}

- ChangePassword endpoint should be accessed by the authenticated user only, so we’ll attribute it with [Authorize] attribute as the below:

[Authorize]
[Route("ChangePassword")]
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
}

Step 6: Consume JSON Web Tokens

Now if we tried to obtain an access token by sending a request to the end point “oauth/token” then try to access one of the protected end points we’ll receive 401 Unauthorized status, the reason for this that our API doesn’t understand those JWT tokens issued by our API yet, to fix this we need to the following:

Install the below NuGet package:

Install-Package Microsoft.Owin.Security.Jwt -Version 3.0.0

The package “Microsoft.Owin.Security.Jwt” is responsible for protecting the Resource server resources using JWT, it only validate and de-serialize JWT tokens.

Now back to our “Startup” class, we need to add the below method “ConfigureOAuthTokenConsumption” as the below:

private void ConfigureOAuthTokenConsumption(IAppBuilder app) {

            var issuer = "http://localhost:59822";
            string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
            byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);

            // Api controllers with an [Authorize] attribute will be validated with JWT
            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { audienceId },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
                    }
                });
        }

This step will configure our API to trust tokens issued by our Authorization server only, in our case the Authorization and Resource Server are the same server (http://localhost:59822), notice how we are providing the values for audience, and the audience secret we used to generate and issue the JSON Web Token in step3.

By providing those values to the “JwtBearerAuthentication” middleware, our API will be able to consume only JWT tokens issued by our trusted Authorization server, any other JWT tokens from any other Authorization server will be rejected.

Lastly we need to call the method “ConfigureOAuthTokenConsumption” in the “Configuration” method as the below:

public void Configuration(IAppBuilder app)
	{
		HttpConfiguration httpConfig = new HttpConfiguration();

		ConfigureOAuthTokenGeneration(app);

		ConfigureOAuthTokenConsumption(app);
		
		//Rest of code is here

	}

Step 7: Final Testing

All the pieces should be in place now, to test this we will obtain JWT access token for the user “SuperPowerUser” by issuing POST request to the end point “oauth/token”

Request JWT Token

Then we will use the JWT received to access protected end point such as “ChangePassword”, if you remember once we added this end point, we were not able to test it directly because it was anonymous and inside its implementation we were calling the method “User.Identity.GetUserId()”. This method will return nothing for anonymous user, but after we’ve added the [Authorize] attribute, any user needs to access this end point should be authenticated and has a valid JWT.

To test this out we will issue POST request to the end point “/accounts/ChangePassword”as the image below, notice he we are sitting the Authorization header using Bearer scheme setting its value to the JWT we received for the user “SuperPwoerUser”. If all is valid we will receive 200 OK status and the user password should be updated.

Change Password Web API

The source code for this tutorial is available on GitHub.

In the next post we’ll see how we’ll implement Roles Based Authorization in our Identity service.

Follow me on Twitter @tjoudeh

References

The post Implement OAuth JSON Web Tokens Authentication in ASP.NET Web API and Identity 2.1 – Part 3 appeared first on Bit of Technology.

ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4

$
0
0

This is the forth part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:

The source code for this tutorial is available on GitHub.

ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API

In the previous post we saw how we can authenticate individual users using the [Authorize] attribute in a very basic form, but there is some limitation with the previous approach where any authenticated user can perform sensitive actions such as deleting any user in the system, getting list of all users in the system, etc… where those actions should be executed only by subset of users with higher privileges (Admins only).

Roles Auth

In this post we’ll see how we can enhance the authorization mechanism to give finer grained control over how users can execute actions based on role membership, and how those roles will help us in differentiate between authenticated users.

The nice thing here that ASP.NET Identity 2.1 provides support for managing Roles (create, delete, update, assign users to a role, remove users from role, etc…) by using the RoleManager<T> class, so let’s get started by adding support for roles management in our Web API.

Step 1: Add the Role Manager Class

The Role Manager class will be responsible to manage instances of the Roles class, the class will derive from “RoleManager<T>”  where T will represent our “IdentityRole” class, once it derives from the “IdentityRole” class a set of methods will be available, those methods will facilitate managing roles in our Identity system, some of the exposed methods we’ll use from the “RoleManager” during this tutorial are:

Method NameUsage
FindByIdAsync(id)Find role object based on its unique identifier
RolesReturns an enumeration of the roles in the system
FindByNameAsync(Rolename)Find roled based on its name
CreateAsync(IdentityRole)Creates a new role
DeleteAsync(IdentityRole)Delete role
RoleExistsAsync(RoleName)Returns true if role already exists

Now to implement the “RoleManager” class, add new file named “ApplicationRoleManager” under folder “Infrastructure” and paste the code below:

public class ApplicationRoleManager : RoleManager<IdentityRole>
    {
        public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
            : base(roleStore)
        {
        }

        public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
        {
            var appRoleManager = new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));

            return appRoleManager;
        }
    }

Notice how the “Create” method will use the Owin middleware to create instances for each request where
Identity data is accessed, this will help us to hide the details of how role data is stored throughout the
application.

Step 2: Assign the Role Manager Class to Owin Context

Now we want to add a single instance of the Role Manager class to each request using the Owin context, to do so open file “Startup” and paste the code below inside method “ConfigureOAuthTokenGeneration”:

private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
	// Configure the db context and user manager to use a single instance per request
	//Rest of code is removed for brevity
	
	app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
	
	//Rest of code is removed for brevity

}

Now a single instance of class “ApplicationRoleManager” will be available for each request, we’ll use this instance in different controllers, so it is better to create a helper property in class “BaseApiController” which all other controllers inherits from, so open file “BaseApiController” and add the following code:

public class BaseApiController : ApiController
{
	//Code removed from brevity
	private ApplicationRoleManager _AppRoleManager = null;

	protected ApplicationRoleManager AppRoleManager
	{
		get
		{
			return _AppRoleManager ?? Request.GetOwinContext().GetUserManager<ApplicationRoleManager>();
		}
	}
}

Step 3: Add Roles Controller

Now we’ll add the controller which will be responsible to manage roles in the system (add new roles, delete existing ones, getting single role by id, etc…), but this controller should only be accessed by users in “Admin” role because it doesn’t make sense to allow any authenticated user to delete or create roles in the system, so we will see how we will use the [Authorize] attribute along with the Roles to control this.

Now add new file named “RolesController” under folder “Controllers” and paste the code below:

[Authorize(Roles="Admin")]
    [RoutePrefix("api/roles")]
    public class RolesController : BaseApiController
    {

        [Route("{id:guid}", Name = "GetRoleById")]
        public async Task<IHttpActionResult> GetRole(string Id)
        {
            var role = await this.AppRoleManager.FindByIdAsync(Id);

            if (role != null)
            {
                return Ok(TheModelFactory.Create(role));
            }

            return NotFound();

        }

        [Route("", Name = "GetAllRoles")]
        public IHttpActionResult GetAllRoles()
        {
            var roles = this.AppRoleManager.Roles;

            return Ok(roles);
        }

        [Route("create")]
        public async Task<IHttpActionResult> Create(CreateRoleBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var role = new IdentityRole { Name = model.Name };

            var result = await this.AppRoleManager.CreateAsync(role);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            Uri locationHeader = new Uri(Url.Link("GetRoleById", new { id = role.Id }));

            return Created(locationHeader, TheModelFactory.Create(role));

        }

        [Route("{id:guid}")]
        public async Task<IHttpActionResult> DeleteRole(string Id)
        {

            var role = await this.AppRoleManager.FindByIdAsync(Id);

            if (role != null)
            {
                IdentityResult result = await this.AppRoleManager.DeleteAsync(role);

                if (!result.Succeeded)
                {
                    return GetErrorResult(result);
                }

                return Ok();
            }

            return NotFound();

        }

        [Route("ManageUsersInRole")]
        public async Task<IHttpActionResult> ManageUsersInRole(UsersInRoleModel model)
        {
            var role = await this.AppRoleManager.FindByIdAsync(model.Id);
            
            if (role == null)
            {
                ModelState.AddModelError("", "Role does not exist");
                return BadRequest(ModelState);
            }

            foreach (string user in model.EnrolledUsers)
            {
                var appUser = await this.AppUserManager.FindByIdAsync(user);

                if (appUser == null)
                {
                    ModelState.AddModelError("", String.Format("User: {0} does not exists", user));
                    continue;
                }

                if (!this.AppUserManager.IsInRole(user, role.Name))
                {
                    IdentityResult result = await this.AppUserManager.AddToRoleAsync(user, role.Name);

                    if (!result.Succeeded)
                    {
                        ModelState.AddModelError("", String.Format("User: {0} could not be added to role", user));
                    }

                }
            }

            foreach (string user in model.RemovedUsers)
            {
                var appUser = await this.AppUserManager.FindByIdAsync(user);

                if (appUser == null)
                {
                    ModelState.AddModelError("", String.Format("User: {0} does not exists", user));
                    continue;
                }

                IdentityResult result = await this.AppUserManager.RemoveFromRoleAsync(user, role.Name);

                if (!result.Succeeded)
                {
                    ModelState.AddModelError("", String.Format("User: {0} could not be removed from role", user));
                }
            }

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            return Ok();
        }
    }

What we have implemented in this lengthy controller code is the following:

  • We have attribute the controller with [Authorize(Roles=”Admin”)] which allows only authenticated users who belong to “Admin” role only to execute actions in this controller, the “Roles” property accepts comma separated values so you can add multiple roles if needed. In other words the user who will have an access to this controller should have valid JSON Web Token which contains claim of type “Role” and value of “Admin”.
  • The method “GetRole(Id)” will return a single role based on it is identifier, this will happen when we call the method “FindByIdAsync”, this method returns object of type “RoleReturnModel” which we’ll create in the next step.
  • The method “GetAllRoles()” returns all the roles defined in the system.
  • The method “Create(CreateRoleBindingModel model)” will be responsible of creating new roles in the system, it will accept model of type “CreateRoleBindingModel” where we’ll create it the next step. This method will call “CreateAsync” and will return response of type “RoleReturnModel”.
  • The method “DeleteRole(string Id)” will delete existing role by passing the unique id of the role then calling the method “DeleteAsync”.
  • Lastly the method “ManageUsersInRole” is proprietary for the AngularJS app which we’ll build in the coming posts, this method will accept a request body containing an object of type “UsersInRoleModel” where the application will add or remove users from a specified role.

Step 4: Add Role Binding Models

Now we’ll add the models used in the previous step, the first class to add will be named “RoleBindingModels” under folder “Models”, so add this file and paste the code below:

public class CreateRoleBindingModel
    {
        [Required]
        [StringLength(256, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 2)]
        [Display(Name = "Role Name")]
        public string Name { get; set; }

    }

    public class UsersInRoleModel {

        public string Id { get; set; }
        public List<string> EnrolledUsers { get; set; }
        public List<string> RemovedUsers { get; set; }
    }

Now we’ll adjust the “ModelFactory” class to include the method which returns the response of type “RoleReturnModel”, so open file “ModelFactory” and paste the code below:

public class ModelFactory
{
	//Code removed for brevity
	
	public RoleReturnModel Create(IdentityRole appRole) {

		return new RoleReturnModel
	   {
		   Url = _UrlHelper.Link("GetRoleById", new { id = appRole.Id }),
		   Id = appRole.Id,
		   Name = appRole.Name
	   };
	}
}

public class RoleReturnModel
{
	public string Url { get; set; }
	public string Id { get; set; }
	public string Name { get; set; }
}

 Step 5: Allow Admin to Manage Single User Roles

Until now the system doesn’t have an endpoint which allow users in Admin role to manage the roles for a selected user, this endpoint will be needed in the AngularJS app,  in order to add it open “AccountsController” class and paste the code below:

[Authorize(Roles="Admin")]
[Route("user/{id:guid}/roles")]
[HttpPut]
public async Task<IHttpActionResult> AssignRolesToUser([FromUri] string id, [FromBody] string[] rolesToAssign)
{

	var appUser = await this.AppUserManager.FindByIdAsync(id);

	if (appUser == null)
	{
		return NotFound();
	}
	
	var currentRoles = await this.AppUserManager.GetRolesAsync(appUser.Id);

	var rolesNotExists = rolesToAssign.Except(this.AppRoleManager.Roles.Select(x => x.Name)).ToArray();

	if (rolesNotExists.Count() > 0) {

		ModelState.AddModelError("", string.Format("Roles '{0}' does not exixts in the system", string.Join(",", rolesNotExists)));
		return BadRequest(ModelState);
	}

	IdentityResult removeResult = await this.AppUserManager.RemoveFromRolesAsync(appUser.Id, currentRoles.ToArray());

	if (!removeResult.Succeeded)
	{
		ModelState.AddModelError("", "Failed to remove user roles");
		return BadRequest(ModelState);
	}

	IdentityResult addResult = await this.AppUserManager.AddToRolesAsync(appUser.Id, rolesToAssign);

	if (!addResult.Succeeded)
	{
		ModelState.AddModelError("", "Failed to add user roles");
		return BadRequest(ModelState);
	}

	return Ok();
}

What we have implemented in this method is the following:

  • This method can be accessed only by authenticated users who belongs to “Admin” role, that’s why we have added the attribute [Authorize(Roles=”Admin”)]
  • The method accepts the UserId in its URI and array of the roles this user Id should be enrolled in.
  • The method will validates that this array of roles exists in the system, if not, HTTP Bad response will be sent indicating which roles doesn’t exist.
  • The system will delete all the roles assigned for the user then will assign only the roles sent in the request.

Step 6: Protect the existing end points with [Authorize(Roles=”Admin”)] Attribute

Now we’ll visit all the end points we have created earlier in the previous posts and mainly in “AccountsController” class. We’ll add add “Roles=Admin” to the Authorize attribute for all the end points the should be accessed only by users in Admin role.

The end points are:

 – GetUsers, GetUser, GetUserByName, and DeleteUser  should be accessed by users enrolled in “Admin” role. The code change will be as simple as the below:

[Authorize(Roles="Admin")]
[Route("users")]
public IHttpActionResult GetUsers()
{}

[Authorize(Roles="Admin")]
[Route("user/{id:guid}", Name = "GetUserById")]
public async Task<IHttpActionResult> GetUser(string Id)
{}


[Authorize(Roles="Admin")]
[Route("user/{username}")]
public async Task<IHttpActionResult> GetUserByName(string username)
{}

[Authorize(Roles="Admin")]
[Route("user/{id:guid}")]
public async Task<IHttpActionResult> DeleteUser(string id)
{}

Step 7: Update the DB Migration File

Last change we need to do here before testing the changes, is to create a default user and assign it to Admin role when the application runs for the first time. To implement this we need to introduce a change to the file “Configuration” under folder “Infrastructure”, so open the files and paste the code below:

internal sealed class Configuration : DbMigrationsConfiguration<AspNetIdentity.WebApi.Infrastructure.ApplicationDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(AspNetIdentity.WebApi.Infrastructure.ApplicationDbContext context)
        {
            //  This method will be called after migrating to the latest version.

            var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            
            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));

            var user = new ApplicationUser()
            {
                UserName = "SuperPowerUser",
                Email = "taiseer.joudeh@gmail.com",
                EmailConfirmed = true,
                FirstName = "Taiseer",
                LastName = "Joudeh",
                Level = 1,
                JoinDate = DateTime.Now.AddYears(-3)
            };

            manager.Create(user, "MySuperP@ss!");

            if (roleManager.Roles.Count() == 0)
            {
                roleManager.Create(new IdentityRole { Name = "SuperAdmin" });
                roleManager.Create(new IdentityRole { Name = "Admin"});
                roleManager.Create(new IdentityRole { Name = "User"});
            }

            var adminUser = manager.FindByName("SuperPowerUser");

            manager.AddToRoles(adminUser.Id, new string[] { "SuperAdmin", "Admin" });
        }
    }

What we have implemented here is simple, we created a default user named “SuperPowerUser”, then created there roles in the system (SuperAdmin, Admin, and User), then we assigned this user to two roles (SuperAdmin, Admin).

In order to fire the “Seed()” method, we have to drop the exiting database, then from package manager console you type 

update-database
 which will create the database on our SQL server based on the connection string we specified earlier and runs the code inside the seed method and creates the user and roles in the system.

Step 7: Test the Role Authorization

Now the code is ready to be tested, first thing to do is to obtain a JWT token for the user “SuperPowerUser”, after you obtain this JWT and if you try to decode it using JWT.io you will notice that this token contains claim of type “Role” as the below:

{
  "nameid": "29e21f3d-08e0-49b5-b523-3d68cf623fd5",
  "unique_name": "SuperPowerUser",
  "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider": "ASP.NET Identity",
  "AspNet.Identity.SecurityStamp": "832d5f6b-e71c-4c31-9fde-07fe92f5ddfd",
  "role": [
    "Admin",
    "SuperAdmin"
  ],
  "Phone": "123456782",
  "Gender": "Male",
  "iss": "http://localhost:59822",
  "aud": "414e1927a3884f68abc79f7283837fd1",
  "exp": 1426115380,
  "nbf": 1426028980
}

Those claims will allow this user to access any endpoint attribute with [Authorize] attribute and locked for users in Roles (Admin or SuperAdmin).

To test this out we’ll create new role named “Supervisor” by issuing HTTP Post to the endpoint (/api/roles/create), and as we stated before this endpoint should be accessed by users in “Admin” role, so we will pass the JWT token in the Authorization header using Bearer scheme as usual, the request will be as the image below:

Create Role

If all is valid we’ll revive HTTP status 201 Created.

In the next post we’ll see how we’ll implement Authorization access using Claims.

The source code for this tutorial is available on GitHub.

Follow me on Twitter @tjoudeh

The post ASP.NET Identity 2.1 Roles Based Authorization with ASP.NET Web API – Part 4 appeared first on Bit of Technology.

ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5

$
0
0

This is the fifth part of Building Simple Membership system using ASP.NET Identity 2.1, ASP.NET Web API 2.2 and AngularJS. The topics we’ll cover are:

The source code for this tutorial is available on GitHub.

ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1

In the previous post we have implemented a finer grained way to control authorization based on the Roles assigned for the authenticated user, this was done by assigning users to a predefined Roles in our system and then attributing the protected controllers or actions by the [Authorize(Roles = “Role(s) Name”)] attribute.

Claims Featured Image

Using Roles Based Authorization for controlling user access will be efficient in scenarios where your Roles do not change too much and the users permissions do not change frequently.

In some applications controlling user access on system resources is more complicated, and having users assigned to certain Roles is not enough for managing user access efficiently, you need more dynamic way to to control access based on certain information related to the authenticated user, this will lead us to control user access using Claims, or in another word using Claims Based Authorization.

But before we dig into the implementation of Claims Based Authorization we need to understand what Claims are!

Note: It is not mandatory to use Claims for controlling user access, if you are happy with Roles Based Authorization and you have limited number of Roles then you can stick to this.

What is a Claim?

Claim is a statement about the user makes about itself, it can be user name, first name, last name, gender, phone, the roles user assigned to, etc… Yes the Roles we have been looking at are transformed to Claims at the end, and as we saw in the previous post; in ASP.NET Identity those Roles have their own manager (ApplicationRoleManager) and set of APIs to manage them, yet you can consider them as a Claim of type Role.

As we saw before, any authenticated user will receive a JSON Web Token (JWT) which contains a set of claims inside it, what we’ll do now is to create a helper end point which returns the claims encoded in the JWT for an authenticated user.

To do this we will create a new controller named “ClaimsController” which will contain a single method responsible to unpack the claims in the JWT and return them, to do this add new controller named “ClaimsController” under folder Controllers and paste the code below:

[RoutePrefix("api/claims")]
    public class ClaimsController : BaseApiController
    {
        [Authorize]
        [Route("")]
        public IHttpActionResult GetClaims()
        {
            var identity = User.Identity as ClaimsIdentity;
            
            var claims = from c in identity.Claims
                         select new
                         {
                             subject = c.Subject.Name,
                             type = c.Type,
                             value = c.Value
                         };

            return Ok(claims);
        }

    }

The code we have implemented above is straight forward, we are getting the Identity of the authenticated user by calling “User.Identity” which returns “ClaimsIdentity” object, then we are iterating over the IEnumerable Claims property and return three properties which they are (Subject, Type, and Value).
To execute this endpoint we need to issue HTTP GET request to the end point “http://localhost/api/claims” and do not forget to pass a valid JWT in the Authorization header, the response for this end point will contain the below JSON object:

[
  {
    "subject": "Hamza",
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "value": "cd93945e-fe2c-49c1-b2bb-138a2dd52928"
  },
  {
    "subject": "Hamza",
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
    "value": "Hamza"
  },
  {
    "subject": "Hamza",
    "type": "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider",
    "value": "ASP.NET Identity"
  },
  {
    "subject": "Hamza",
    "type": "AspNet.Identity.SecurityStamp",
    "value": "a77594e2-ffa0-41bd-a048-7398c01c8948"
  },
  {
    "subject": "Hamza",
    "type": "iss",
    "value": "http://localhost:59822"
  },
  {
    "subject": "Hamza",
    "type": "aud",
    "value": "414e1927a3884f68abc79f7283837fd1"
  },
  {
    "subject": "Hamza",
    "type": "exp",
    "value": "1427744352"
  },
  {
    "subject": "Hamza",
    "type": "nbf",
    "value": "1427657952"
  }
]

As you noticed from the response above, all the claims contain three properties, and those properties represents the below:

  • Subject: Represents the identity which those claims belongs to, usually the value for the subject will contain the unique identifier for the user in the system (Username or Email).
  • Type: Represents the type of the information contained in the claim.
  • Value: Represents the claim value (information) about this claim.

Now to have better understanding of what type of those claims mean let’s take a look the table below:

SubjectTypeValueNotes
Hamzanameidentifiercd93945e-fe2c-49c1-b2bb-138a2dd52928Unique User Id generated from Identity System
HamzanameHamzaUnique Username
HamzaidentityproviderASP.NET IdentityHow user has been authenticated using ASP.NET Identity
HamzaSecurityStampa77594e2-ffa0-41bd-a048-7398c01c8948Unique Id which stays the same until any security related attribute change, i.e. change user password
Hamzaisshttp://localhost:59822Issuer of the Access Token (Authz Server)
Hamzaaud414e1927a3884f68abc79f7283837fd1For which system this token is generated
Hamzaexp1427744352Expiry time for this access token (Epoch)
Hamzanbf1427657952When this token is issued (Epoch)

After we have briefly described what claims are, we want to see how we can use them to manage user assess, in this post I will demonstrate three ways of using the claims as the below:

  1. Assigning claims to the user on the fly based on user information.
  2. Creating custom Claims Authorization attribute.
  3. Managing user claims by using the “ApplicationUserManager” APIs.

Method 1: Assigning claims to the user on the fly

Let’s assume a fictional use case where our API will be used in an eCommerce website, where certain users have the ability to issue refunds for orders if there is incident happen and the customer is not happy.

So certain criteria should be met in order to grant our users the privileges to issue refunds, the users should have been working for the company for more than 90 days, and the user should be in “Admin”Role.

To implement this we need to create a new class which will be responsible to read authenticated user information, and based on the information read, it will create a single claim or set of claims and assign then to the user identity.
If you recall from the first post of this series, we have extended the “ApplicationUser” entity and added a property named “JoinDate” which represent the hiring date of the employee, based on the hiring date, we need to assign a new claim named “FTE” (Full Time Employee) for any user who has worked for more than 90 days. To start implementing this let’s add a new class named “ExtendedClaimsProvider” under folder “Infrastructure” and paste the code below:

public static class ExtendedClaimsProvider
    {
        public static IEnumerable<Claim> GetClaims(ApplicationUser user)
        {
          
            List<Claim> claims = new List<Claim>();

            var daysInWork =  (DateTime.Now.Date - user.JoinDate).TotalDays;

            if (daysInWork > 90)
            {
                claims.Add(CreateClaim("FTE", "1"));
               
            }
            else {
                claims.Add(CreateClaim("FTE", "0"));
            }

            return claims;
        }

        public static Claim CreateClaim(string type, string value)
        {
            return new Claim(type, value, ClaimValueTypes.String);
        }

    }

The implementation is simple, the “GetClaims” method will take ApplicationUser object and returns a list of claims. Based on the “JoinDate” field it will add new claim named “FTE” and will assign a value of “1” if the user has been working for than 90 days, and a value of “0” if the user worked for less than this period. Notice how I’m using the method “CreateClaim” which returns a new instance of the claim.

This class can be used to enforce creating custom claims for the user based on the information related to her, you can add as many claims as you want here, but in our case we will add only a single claim.

Now we need to call the method “GetClaims” so the “FTE” claim will be associated with the authenticated user identity, to do this open class “CustomOAuthProvider” and in method “GrantResourceOwnerCredentials” add the highlighted line (line 7) as the code snippet below:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
	//Code removed for brevity

	ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
	
	oAuthIdentity.AddClaims(ExtendedClaimsProvider.GetClaims(user));
	
	var ticket = new AuthenticationTicket(oAuthIdentity, null);
	
	context.Validated(ticket);
   
}

Notice how the established claims identity object “oAuthIdentity” has a method named “AddClaims” which accepts IEnumerable object of claims, now the new “FTE” claim is assigned to the authenticated user, but this is not enough to satisfy the criteria needed to issue the fictitious refund on orders, we need to make sure that the user is in “Admin” Role too.

To implement this we’ll create a new Role on the fly based on the claims assigned for the user, in other words we’ll create Roles from the Claims user assigned to, this Role will be named “IncidentResolvers”. And as we stated in the beginning of this post, the Roles eventually are considered as a Claim of type Role.

To do this add new class named “RolesFromClaims” under folder “Infrastructure” and paste the code below:

public class RolesFromClaims
    {
        public static IEnumerable<Claim> CreateRolesBasedOnClaims(ClaimsIdentity identity)
        {
            List<Claim> claims = new List<Claim>();

            if (identity.HasClaim(c => c.Type == "FTE" && c.Value == "1") &&
                identity.HasClaim(ClaimTypes.Role, "Admin"))
            {
                claims.Add(new Claim(ClaimTypes.Role, "IncidentResolvers"));
            }

            return claims;
        }
    }

The implementation is self explanatory, we have created a method named “CreateRolesBasedOnClaims” which accepts the established identity object and returns a list of claims.

Inside this method we will check that the established identity for the authenticated user has a claim of type “FTE” with value “1”, as well that the identity contains a claim of type “Role” with value “Admin”, if those 2 conditions are met then; we will create a new claim of Type “Role” and give it a value of “IncidentResolvers”.
Last thing we need to do here is to assign this new set of claims to the established identity, so to do this open class “CustomOAuthProvider” again and in method “GrantResourceOwnerCredentials” add the highlighted line (line 9) as the code snippet below:

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
	//Code removed for brevity

	ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
	
	oAuthIdentity.AddClaims(ExtendedClaimsProvider.GetClaims(user));
	
	oAuthIdentity.AddClaims(RolesFromClaims.CreateRolesBasedOnClaims(oAuthIdentity));
	
	var ticket = new AuthenticationTicket(oAuthIdentity, null);
	
	context.Validated(ticket);
   
}

Now all the new claims which created on the fly are assigned to the established identity and once we call the method “context.Validated(ticket)”, all claims will get encoded in the JWT token, so to test this out let’s add fictitious controller named “OrdersController” under folder “Controllers” as the code below:

[RoutePrefix("api/orders")]
public class OrdersController : ApiController
{
	[Authorize(Roles = "IncidentResolvers")]
	[HttpPut]
	[Route("refund/{orderId}")]
	public IHttpActionResult RefundOrder([FromUri]string orderId)
	{
		return Ok();
	}
}

Notice how we attribute the action “RefundOrder” with  [Authorize(Roles = “IncidentResolvers”)] so only authenticated users with claim of type “Role” and has the value of “IncidentResolvers” can access this end point. To test this out you can issue HTTP PUT request to the URI “http://localhost/api/orders/refund/cxy-4456393″ with an empty body.

As you noticed from the first method, we have depended on user information to create claims and kept the authorization more dynamic and flexible.
Keep in mind that you can add your access control business logic, and have finer grained control on authorization by implementing this logic into classes “ExtendedClaimsProvider” and “RolesFromClaims”.

Method 2: Creating custom Claims Authorization attribute

Another way to implement Claims Based Authorization is to create a custom authorization attribute which inherits from “AuthorizationFilterAttribute”, this authorize attribute will check directly the claims value and type for the established identity.

To do this let’s add new class named “ClaimsAuthorizationAttribute” under folder “Infrastructure” and paste the code below:

public class ClaimsAuthorizationAttribute : AuthorizationFilterAttribute
    {
        public string ClaimType { get; set; }
        public string ClaimValue { get; set; }

        public override Task OnAuthorizationAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
        {

            var principal = actionContext.RequestContext.Principal as ClaimsPrincipal;

            if (!principal.Identity.IsAuthenticated)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                return Task.FromResult<object>(null);
            }

            if (!(principal.HasClaim(x => x.Type == ClaimType && x.Value == ClaimValue)))
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                return Task.FromResult<object>(null);
            }

            //User is Authorized, complete execution
            return Task.FromResult<object>(null);

        }
    }

What we’ve implemented here is the following:

  • Created a new class named “ClaimsAuthorizationAttribute” which inherits from “AuthorizationFilterAttribute” and then override method “OnAuthorizationAsync”.
  • Defined 2 properties “ClaimType” & “ClaimValue” which will be used as a setters when we use this custom authorize attribute.
  • Inside method “OnAuthorizationAsync” we are casting the object “actionContext.RequestContext.Principal” to “ClaimsPrincipal” object and check if the user is authenticated.
  • If the user is authenticated we’ll look into the claims established for this identity if it has the claim type and claim value.
  • If the identity contains the same claim type and value; then we’ll consider the request authentic and complete the execution, other wist we’ll return 401 unauthorized status.

To test the new custom authorization attribute, we’ll add new method to the “OrdersController” as the code below:

[ClaimsAuthorization(ClaimType="FTE", ClaimValue="1")]
[Route("")]
public IHttpActionResult Get()
{
	return Ok();
}

Notice how we decorated the “Get()” method with the “[ClaimsAuthorization(ClaimType=”FTE”, ClaimValue=”1″)]” attribute, so any user has the claim “FTE” with value “1” can access this protected end point.

Method 3: Managing user claims by using the “ApplicationUserManager” APIs

The last method we want to explore here is to use the “ApplicationUserManager” claims related API to manage user claims and store them in ASP.NET Identity related tables “AspNetUserClaims”.

In the previous two methods we’ve created claims for the user on the fly, but in method 3 we will see how we can add/remove claims for a certain user.

The “ApplicationUserManager” class comes with a set of predefined APIs which makes dealing and managing claims simple, the APIs that we’ll use in this post are listed in the table below:

Method NameUsage
AddClaimAsync(id, claim)Create a new claim for specified user id
RemoveClaimAsync(id, claim)Remove claim from specified user if claim type and value match
GetClaimsAsync(id)Return IEnumerable of claims based on specified user id

To use those APIs let’s add 2 new methods to the “AccountsController”, the first method “AssignClaimsToUser” will be responsible to add new claims for specified user, and the second method “RemoveClaimsFromUser” will remove claims from a specified user as the code below:

[Authorize(Roles = "Admin")]
[Route("user/{id:guid}/assignclaims")]
[HttpPut]
public async Task<IHttpActionResult> AssignClaimsToUser([FromUri] string id, [FromBody] List<ClaimBindingModel> claimsToAssign) {

	if (!ModelState.IsValid)
	{
		return BadRequest(ModelState);
	}

	 var appUser = await this.AppUserManager.FindByIdAsync(id);

	if (appUser == null)
	{
		return NotFound();
	}

	foreach (ClaimBindingModel claimModel in claimsToAssign)
	{
		if (appUser.Claims.Any(c => c.ClaimType == claimModel.Type)) {
		   
			await this.AppUserManager.RemoveClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
		}

		await this.AppUserManager.AddClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
	}
	
	return Ok();
}

[Authorize(Roles = "Admin")]
[Route("user/{id:guid}/removeclaims")]
[HttpPut]
public async Task<IHttpActionResult> RemoveClaimsFromUser([FromUri] string id, [FromBody] List<ClaimBindingModel> claimsToRemove)
{

	if (!ModelState.IsValid)
	{
		return BadRequest(ModelState);
	}

	var appUser = await this.AppUserManager.FindByIdAsync(id);

	if (appUser == null)
	{
		return NotFound();
	}

	foreach (ClaimBindingModel claimModel in claimsToRemove)
	{
		if (appUser.Claims.Any(c => c.ClaimType == claimModel.Type))
		{
			await this.AppUserManager.RemoveClaimAsync(id, ExtendedClaimsProvider.CreateClaim(claimModel.Type, claimModel.Value));
		}
	}

	return Ok();
}

The implementation for both methods is very identical, as you noticed we are only allowing users in “Admin” role to access those endpoints, then we are specifying the UserId and a list of the claims that will be add or removed for this user.

Then we are making sure that user specified exists in our system before trying to do any operation on the user.

In case we are adding a new claim for the user, we will check if the user has the same claim type before trying to add it, add if it exists before we’ll remove this claim and add it again with the new claim value.

The same applies when we try to remove a claim from the user, notice that methods “AddClaimAsync” and “RemoveClaimAsync” will save the claims permanently in our SQL data-store in table “AspNetUserClaims”.

Do not forget to add the “ClaimBindingModel” under folder “Models” which acts as our POCO class when we are sending the claims from our front-end application, the class will contain the code below:

public class ClaimBindingModel
    {
        [Required]
        [Display(Name = "Claim Type")]
        public string Type { get; set; }

        [Required]
        [Display(Name = "Claim Value")]
        public string Value { get; set; }
    }

There is no extra steps needed in order to pull those claims from the SQL data-store when establishing the user identity, thanks for the method “CreateIdentityAsync” which is responsible to pull all the claims for the user. We have already implemented this and it can be checked by visiting the highlighted LOC.

To test those methods all you need to do is to issue HTTP PUT request to the URI: “http://localhost:59822/api/accounts/user/{UserId}/assignclaims” and “http://localhost:59822/api/accounts/user/{UserId}/removeclaims” as the request images below:

Assign Claims

Assign Claims

Remove Claims

Remove Claims

That’s it for now folks about implementing Authorization using Claims.

In the next post we’ll build a simple AngularJS application which connects all those posts together, this post should be interesting :)

The source code for this tutorial is available on GitHub.

Follow me on Twitter @tjoudeh

References

The post ASP.NET Web API Claims Authorization with ASP.NET Identity 2.1 – Part 5 appeared first on Bit of Technology.


Azure Active Directory B2C Overview and Policies Management – Part 1

$
0
0

Prior joining Microsoft I was heavily involved in architecting and building a large scale HTTP API which will be consumed by a large number of mobile application consumers on multiple platforms (iOS, Android, and Windows Phone). Securing the API and architecting the Authentication and Authorization part for the API was one of the large and challenging features which we built from scratch as we needed only to support local database account (allowing users to login using their own existing email/username and password). As well writing a proprietary code for each platform to consume the Authentication and Authorization end points, storing the tokens, and refresh them silently was a bit challenging and required skilled mobile apps developers to implement it securely on the different platforms. Don’t ask me why we didn’t use Xamarin for cross-platform development, it is a long story 🙂 During developing the back-end API I have learned that building identity management solution is not a trivial feature, and it is better to outsource it to a cloud service provider if this is a feasible option and you want your dev team to focus on building what matters; your business features!

Recently Microsoft has announced the general availability in North America data centers of a service named “Azure Active Directory B2C” which in my humble opinion will fill the gap of having a cloud identity and access management service targeted especially for mobile apps and web developers who need to build apps for consumers; consumers who want to sign in with their existing email/usernames, create new app-specific local accounts, or use their existing social accounts (Facebook, Google, LinkedIn, Amazon, Microsoft account) to sign in into the mobile/web app.

Azure Active Directory B2C

The Azure Active Directory B2C will allow backend developers to focus on the core business of their services while they outsource the identity management to Azure Active Directory B2C including (Signing-in, Signing-up, Password reset, Edit Profile, etc..). One important feature to mention here that the service can run on Azure cloud while your HTTP API is hosted on-premise, there is no need to have everything in the cloud if your use case requires hosting your services on-premise.  You can read more about all the features of Azure Active Directory B2C by visiting their official page.

The Azure Active Directory B2C can integrate seamlessly with the new unified authentication library named MSAL (Microsoft Authentication Library), this library will help developers to obtain tokens from Active Directory, Azure Active Directory B2C, and MSA for accessing protected resources. The library will support different platforms covering: .NET 4.5 + (Desktop Apps and Web apps), Windows Universal Apps, Windows Store apps (Windows 8 and above), iOS (via Xamarin), Android (via Xamarin), and .Net Core. Library still in preview, it should not be used in production application yet.

So during this series of posts, I will be covering different aspects of Azure Active Directory B2C as well integrating it with MSAL (Microsoft Authentication Library) in different front-end platforms (Desktop Application and Web Application).

Azure Active Directory B2C Overview and Policies Management

The source code for this tutorial is available on GitHub.

The Web API has been published on Azure App Services, so feel free to try it out using the Base URL (https://aadb2cresourceapi.azurewebsites.net/)

I broke down this series into multiple posts which I’ll be posting gradually, posts are:

What we’ll build in this tutorial?

During this post we will build a Web API 2 HTTP API which will be responsible for managing shipping orders (i.e. Listing orders, adding new ones, etc…), the orders data will be stored in Azure Table Storage, while we will outsource all the identity management to Azure Active Directory B2C, where service users/consumers will rely on AAD B2C to signup new accounts using their app-specific email/password, then allow them to login using their app-specific accounts.

Saying this we need a front-end apps to manipulate orders and communicate with the HTTP API, We will build a different type of apps during the series of posts where some of them will use MSAL.

So the components that all the tutorials will be built from are:

  • Azure Active Directory B2C tenant for identity management, it will act as our IdP (Identity Provider).
  • ASP.NET Web API 2 acting as HTTP API Service and secured by the Azure Active Directory B2C tenant.
  • Different front end apps which will communicate with Azure Active Directory B2C to sign-in users, obtain tokens, send them to the protected HTTP API, and retrieve results from the HTTP API and project it on the front end applications.

So let’s get our hands dirty and start building the tutorial.

Building the Back-end Resource (Web API)

Step 1: Creating the Web API Project

In this tutorial, I’m using Visual Studio 2015 and .Net framework 4.5.2, to get started create an empty solution and name it “WebApiAzureAcitveDirectoryB2C.sln”, then add new empty ASP.NET Web application named “AADB2C.Api”, the selected template for the project will be “Empty” template with no core dependencies, check the image below:

VS2015 Web Api Template

Once the project has been created, click on it’s properties and set “SSL Enabled” to “True”, copy the “SSL URL” value and right lick on project, select “Properties”, then select the “Web” tab from the left side and paste the “SSL URL” value in the “Project Url” text field and click “Save”. We need to allow https scheme locally once we debug the application. Check the image below:

Web Api SSL Enable

Note: If this is the first time you enable SSL locally, you might get prompted to install local IIS Express Certificate, click “Yes”.

Step 2: Install the needed NuGet Packages to bootstrap the API

This project is empty so we need to install the NuGet packages needed to setup our Owin server and configure ASP.NET Web API 2 to be hosted within an Owin server, so open NuGet Package Manager Console and install the below packages:

Install-Package Microsoft.AspNet.WebApi -Version 5.2.3
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.3
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.1

Step 3: Add Owin “Startup” Class

We need to build the API components because we didn’t use a ready made template, this way is cleaner and you understand the need and use for each component you install in your solution, so add a new class named “Startup”. It will contain the code below, please note that the method “ConfigureAuth” is left empty intentionally as we will visit this class many times after we create our Azure Active Directory B2C tenant, what I need to do now is to build the API without anything protection then protect with our new Azure Active Directory B2C IdP:

public class Startup
    {

        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            // Web API routes
            config.MapHttpAttributeRoutes();

            ConfigureOAuth(app);

            app.UseWebApi(config);

        }

        public void ConfigureOAuth(IAppBuilder app)
        {
           
        }
    }

Step 4: Add support to store data on Azure Table Storage

Note: I have decided to store the fictitious data about customers orders in Azure table storage as this service will be published online and I need to demonstrate the features on how to distinguish users data based on the signed-in user, feel free to use whatever permanent storage you like to complete this tutorial, the implementation here is simple so you can replace it with a SQL Server, MySQL, or any other NoSQL store.

So let’s add the needed NuGet packages which allow us to access the Azure Table Storage in a .NET client, I recommend you to refer to the official documentation if you need to read more about Azure Table Storage.

Install-Package WindowsAzure.Storage
Install-Package Microsoft.WindowsAzure.ConfigurationManager

Step 5: Add Web API Controller responsible for orders management

Now we want to add a controller which is responsible for orders management (Adding orders, listing all orders which belong to a certain user) . So add new controller named “OrdersController” inside a folder named “Controllers” and paste the code below:

[RoutePrefix("api/Orders")]
    public class OrdersController : ApiController
    {
        CloudTable cloudTable = null;

        public OrdersController()
        {
            // Retrieve the storage account from the connection string.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));

            // Create the table client.
            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

            // Retrieve a reference to the table.
            cloudTable = tableClient.GetTableReference("orders");

            // Create the table if it doesn't exist.
            // Uncomment the below line if you are not sure if the table has been created already
            // No need to keep checking that table exixts or not.
            //cloudTable.CreateIfNotExists();
        }

        [Route("")]
        public IHttpActionResult Get()
        {
         
            //This will be read from the access token claims.
            var userId = "TaiseerJoudeh";

            TableQuery <OrderEntity> query = new TableQuery<OrderEntity>()
                .Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, userId));

            var orderEntitis = cloudTable.ExecuteQuery(query).Select(
                o => new OrderModel() {
                OrderID = o.RowKey,
                ShipperName = o.ShipperName,
                ShipperCity = o.ShipperCity,
                TS = o.Timestamp
                });

            return Ok(orderEntitis);
        }

        [Route("")]
        public IHttpActionResult Post (OrderModel order)
        {
            //This will be read from the access token claims.
            var userId = "TaiseerJoudeh";

            OrderEntity orderEntity = new OrderEntity(userId);

            orderEntity.ShipperName = order.ShipperName;
            orderEntity.ShipperCity = order.ShipperCity;

            TableOperation insertOperation = TableOperation.Insert(orderEntity);

            // Execute the insert operation.
            cloudTable.Execute(insertOperation);

            order.OrderID = orderEntity.RowKey;

            order.TS = orderEntity.Timestamp;

            return Ok(order);
        }
    }

    #region Classes

    public class OrderModel
    {
        public string OrderID { get; set; }
        public string ShipperName { get; set; }
        public string ShipperCity { get; set; }
        public DateTimeOffset TS { get; set; }
    }

    public class OrderEntity : TableEntity
    {
        public OrderEntity(string userId)
        {
            this.PartitionKey = userId;
            this.RowKey = Guid.NewGuid().ToString("N");
        }

        public OrderEntity() { }

        public string ShipperName { get; set; }

        public string ShipperCity { get; set; }

    }

    #endregion

What we have implemented above is very straight forward, in the constructor of the controller, we have read the connection string for the Azure Table Storage from the web.config and created a cloud table instance which references the table named “Orders”. This table will hold the Orders data.

The structure of the table is you are thinking in SQL context even Azure Table Storage is NoSQL store is simple and it is represented in the class named “OrderEntity”, the “PartitionKey” will represent the “UserId”, and the “RowKey” will represent the “OrderId”. The “OrderId” will always contain an auto generated value.

Please note the following: a) You should not store the connection string for the table storage in web.config, it is better to use Azure Key Vault for a secure way to store your keys or you can set from Azure App Settings if you are going to host the Api on Azure. b) The “UserId” now is fixed, but eventually, it will read the authenticated UserId from the access token claims once we establish the IdP provider and configure our API to rely on Azure Active Directory B2C to protect it.

By taking a look at the “POST” action, you will notice that we are adding a new record to the table storage, and the “UserId” is fixed for now and we will visit this and fix it. The same applies to the “GET” action where we read the data from Azure Table Storage for a fixed user.

Now the API is ready for testing, you can issue a GET request or POST request and the data will be stored under the fixed “UserId” which is “TaiseerJoudeh”. Note that there is no Authorization header set as the API still publicly available for anyone. Below is a reference for the POST request:

POST Request:

POST /api/orders HTTP/1.1
Host: localhost:44339
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: 6f1164fa-8560-98fd-6566-892517f1003e

{
    "shipperName" :"Nike",
    "shipperCity": "Clinton"
}

Configuring the Azure Active Directory B2C Tenant

Step 5: Create an Azure Active Directory B2C tenant

Now we need to create the Azure Active Directory B2C tenant, for the mean time you can create it from the Azure Classic Portal and you will be able to manage all the settings from the new Azure Preview Portal.

  • To start the creation process login to the classic portal and navigate to: New > App Services > Active Directory > Directory > Custom Create as the image below:

Azure AD B2C Directory

  • A new popup will appear as the image below asking you to fill some information, note that if you selected one of the following countries (United States, Canada, Costa Rica, Dominican Republic, El Salvador, Guatemala, Mexico, Panama, Puerto Rico and Trinidad and Tobago) your Azure AD B2C will be Production-Scale tenant, as Azure AD B2C is GA only in the countries listed (North America). This will change in the coming months and more countries will be announced as GA. You can read more about the road map of Azure AD B2C here. Do not forget to check “This is a B2C directory” for sure 🙂

Azure AD B2C New Directory

  • After your tenant has been created, it will appear in the Active Directory extension bar, as the image below; select the tenant and click on “Configure” tab,  then click on “Manage B2C Settings” as the image below. This will open the new Azure Preview Portal where we will start registering the App and managing policies there.

Azure AD B2C Manage Settings

Step 6: Register our application in Azure AD B2C tenant

Now we need to register the application under the tenant we’ve created, this will allow us to add the sign-in, sign-up, edit profile features in our app, to do so follow the below steps:

  • Select “Applications” from the “Settings” blade for the B2C tenant we’ve created, then click on the “Add” Icon on the top
  • A new blade will open asking you to fill the following information
    • Name: This will be the application name that will describe your application to consumers. In our case I have used “BitofTech Demo App”
    • Web API/Web APP: we need to turn this on as we are protecting a Web Api and Web app.
    • Allow implicit flow: We will turn this on as well as we need to use OpenId connect protocol to obtain an id token
    • Reply URL: those are the registered URLs where the Azure Active Directory B2C will send the authentication response to (tokens) or error responses to. The client applications calling the API can specify the Reply URL, but it should be registered in the tenant by the administrator in order to work. In our case I will put the Reply URL now to the Web API URL which is “https://localhost:44339/” this will be good for testing purposes but in the next post I will add another URL for the Web application we will build to consume the API. As you notice you can register many Reply URLs so you can support different environments (Dev, staging, production, etc…)
    • Native Client: You need to turn this on if you are building mobile application or desktop application client, for the mean time there is no need to turn it on as we are building web application (Server side app) but we will visit this again in the coming posts and enable this once we build a desktop app to consume the API.
    • App key or App secret: This will be used to generate a “Client Secret” for the App which is needed to authenticate the App in the Authorization/Hybrid OAuth 2.0 flow. We will need this in the future posts once I describe how we can obtain access tokens, open id tokens and refresh tokens using Raw HTTP requests. For the mean time, there is no need to generate an App key.
  • One you fill all the information, click “Save” and the application will be created and Application ID will be generated, copy this value and keep it on the notepad as we will use it later on.
  • below an image which shows the App after filling the needed information:

Azure AD B2C New App

Step 7: Selecting Identity Providers

Azure Active Directory B2C offers multiple social identity providers Microsoft, Google, Amazon, LinkedIn and Facebook in addition to the local App-specific accounts. The local account can be configured to use a “Username” or “Email” as a unique attribute for the account, we will use the “Email” and we will use only the local accounts in this tutorial to keep things simple and straight forward.

You can change the “Identity Providers” by selecting the “Identity providers” blade. This link will be helpful if you need to configure it.

Step 8: Add custom attributes

Azure AD B2C directory comes with a set of “built-in” attributes that represents information about the user, attributes such as (Email, First name, Last name, etc…) those attributes can be extended in case you needed to add extra information about the user upon signing up (creating a profile) or editing it.

At the mean time you can create an attribute and set the datatype for it as “String”, I believe that this limitation would be resolved in the coming releases.

To do so select “User attributes” blade and click on the “Add” icon, a new blade will open asking you to fill the attribute name, data type and description. In our case, I’ve added an attribute named “Gender” to capture the gender of the user during the registration process (profile creation or sign up). Below an image which represents this process:

B2C Custom Attribute

We will see in the next steps how we can retrieve this custom attribute value in our application, there are 2 ways to do so, first one is to include it in claims encoded in the token and the second one is to use Azure AD Graph API. We will use the first method.

In the next step, I will show you how to include this custom attribute in the sign-up policy.

Step 9: Creating different policies

The unique thing about Azure Active Directory B2C is using the extensible policy framework, which allows the developers to define an easy and reusable way to build the identity experience that they want to provide for application consumers (end users). So for example to enroll a new user in your app and create a app-specific local account, you need to create a Signup Policy where you configure the attributes needed to capture it from the user, you configure the attributes (claims) you need to retrieve after successfully executing the policy, you can configure which identity providers consumers are allowed to use, as well you can configure the look and feel for the signup page by doing simple modifications such as changing label names, the order of the fields, or replace the UI entirety (more about this in future post). All this applies to other policies used to implement identity features such as signing in, editing profile.

As well by using the extensible policies framework we can create multiple policies of different types in our tenant and use them in our applications as needed. Policies can be reused across applications, as well they can be exported and uploaded for easier management. This allows us to define and modify identity experiences with minimal or no changes to application code.

Now let’s create the first policy which is the “Signup” policy which will build the experience for users during the signup process and I show you how to test it out. to do so follow the below steps:

  • Select the “Sign-up” policies.
  • Click on the “Add” icon at the top of the blade.
  • Select a name for the policy, picking up a clear name is important as we will reference the name in our application, in our case I’ve used “signup”.
  • Select the “Identity providers” and select “Email signup”. In our case this the only provider we have configured for this tenant so far.
  • Select the “Sign-up” attributes. Now we have the chance to choose the attributes we want to collect from the user during the signup process. I have selected 6 attributes as the image below.
  • Select the “Application claims”. Now we have the chance to choose the claims we want to return in the tokens sent back to out application after a successful signup process, remember that those claims are encoded within the token so do not get crazy about adding many claims as the token size will increase. I have selected 9 claims as the image below.
  • Finally, click on “Create” button.

Signup Policy Attribute

Notes:

  • The policy that will be created will be named as “B2C_1_signup” all the policies will be prefixed by “B2C_1_” fragment, do not ask me why but it seems its implementation detail 🙂
  • You can change the attribute label names (Surname -> Last Name) as well change the order of the fields by dragging the attributes, and set if the field is mandatory or not. Notice how I changed the custom attribute “Gender” to display as a drop down list and have a fixed items such as “Male” and “Female”. All this can be done by selecting the “Page UI customization” section.
  • Once the policy has been created you can configure the ID token, and refresh token expiration date time by selecting the section “Toke, session & SSO config”. I will cover this in the coming posts, for now we will keep the defaults for all policies we will create, and you can read more about this here.
  • Configuring ID token and refresh token expiration times is done pair policy not tenant, IMO I do not know why this was not done per tenant, not per policy, this for sure gives you better flexibility and finer grained control on how to manage policies, but I can not think of a use case where you want to have a different expiration dates for different policies. We will keep them the same for all policies we will create unless we are testing out something.
  • Below an image on how to change the custom attribute “Gender” order between other fields as well how to the “User input type” to use Drop down list:

Azure B2C Edit Attribute

Step 10: Creating the Sign in and Edit Profile policies

I won’t bore you with the repeated details for creating the other 2 policies which will be using during this tutorial, they all follow the same approach I have illustrated in the previous step. Please note the below about the newly created policies:

  • The policy which will be used to sign in the user (login) will be named “Signin“, so after creating it will be named “B2C_1_Signin“.
  • The policy which will be used to edit the created profile will be named “Editprofile“, so after creating it will be named “B2C_1_Editprofile“.
  • Do not forget to configure the Gender custom attribute for the “Editprofile” policy, as we need to display the values in the drop-down list instead of a text box.
  • Select the same claims we have already selected for the signup policy (8 claims)
  • You can click “Run now” button and test the new policies using a user that you already created from the sign up policy (Jump to next step before).
  • At the mean time the only way to execute those policies and test them out in this post and the coming one is to use the “Run now” button until I build a web application which communicates with the Web API and Azure Active Directory B2C tenant.

Step 11: Testing the created signup policy in Azure AD B2C tenant

Azure Active Directory B2C provide us with the ability to test the policies locally without leaving the azure portal, to do so all you need to click on is the “Run now” button and select the preferred Reply URL in case you registered many Reply URL once you registered the App, in our case we will have only a single app and a single reply URL. The Reply URL will be used to return the Id token in hash fragment to the Reply URL selected.

Once you click “Run now” button a new window will open and you will be able to test the sign up policy by filling up the needed information, notice that you need to use a real email in order to send activation code to it and verify that you own this email, I believe the Azure AD team implemented by verifying the email before creating the account to avoid creating many unreal emails that will never get verified. Smart decision.

Once you receive the verification email with the six digit code, you need to enter it in the verification code text box and click on “verify”, if all is good the “Create” button is enabled and you can complete filling the profile. You can change the content of the email by following this link

The password policy (complexity) used here is the same one used in Azure Active Directory, you can read more about it here.

After you fill all the mandatory attributes as the image below click create and you will notice that a redirect took place to the Reply URL and there is an Id Token returned as a hash fragment. This Id token contains all the claims specified in the policy, you can test it out by using a JWT debugging tool such as calebb.net so if we tried to debug the token we’ve received after running the sign up policy, you will see all the claims we asked for encoded in this JWT token.

Azure AD B2C Signup Test

Notes about the claims:

  • The newly “Gender” custom attribute we have added is returned under a claim named “extension_Gender“. It seems that all the custom attributed are prefixed by the phrase “extension”, I need to validate this with Azure AD team.
  • The globally user unique identifier is returned in the claim named “oid”, we will depend on this claim value to distinguish between registered users.
  • This token is generated based on the policy named “B2C_1_signup”, note the claim named “tfp”.

To have a better understanding of each claim meaning, please check this link.

{
  "exp": 1471954089,
  "nbf": 1471950489,
  "ver": "1.0",
  "iss": "https://login.microsoftonline.com/tfp/3d960283-c08d-4684-b378-2a69fa63966d/b2c_1_signup/v2.0/",
  "sub": "Not supported currently. Use oid claim.",
  "aud": "bc348057-3c44-42fc-b4df-7ef14b926b78",
  "nonce": "defaultNonce",
  "iat": 1471950489,
  "auth_time": 1471950489,
  "oid": "31ef9c5f-6416-48b8-828d-b6ce8db77d61",
  "emails": [
    "ahmad.hasan@gmail.com"
  ],
  "newUser": true,
  "given_name": "Ahmad",
  "family_name": "Hasan",
  "extension_Gender": "M",
  "name": "Ahmad Hasan",
  "country": "Jordan",
  "tfp": "B2C_1_signup"
}

This post turned out to be longer than anticipated so I will complete in the coming post , in the next post where I will show you how to reconfigure Our Web Api project to rely on out Azure AD B2C IdP and validate those tokens.

The Source code for this tutorial is available on GitHub.

Follow me on Twitter @tjoudeh

Resources

The post Azure Active Directory B2C Overview and Policies Management – Part 1 appeared first on Bit of Technology.

Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3

$
0
0

This is the third part of the tutorial which will cover Using Azure AD B2C tenant with ASP.NET Web API 2 and various front-end clients.

The source code for this tutorial is available on GitHub.

The MVC Web App has been published on Azure App Services, so feel free to try it out using the Base URL (https://aadb2cmvcapp.azurewebsites.net/)

I promise you that I won’t share your information with anyone, feel free to try the experience 🙂

Integrate Azure AD B2C with ASP.NET MVC Web App

In the previous post, we have configured our Web API to rely on our Azure AD B2C IdP to secure it so only calls which contain a token issued by our IdP will be accepted by our Web API.

In this post we will build our first front-end application (ASP.NET MVC 5 Web App) which will consume the API endpoints by sending a valid token obtained from the Azure AD b2C tenant, as well it will allow anonymous users to create profiles, and sign in against the Azure B2C tenant. The MVC Web app itself will be protected as well by the same Azure AD B2C tenant as we will share the same tenant Id between the Web API and MVC Web app.

So let’s start building the MVC Web App.

Step 1: Creating the MVC Web App Project

Let’s add a new ASP.NET Web application named “AADB2C.WebClientMvc” to the solution named “WebApiAzureAcitveDirectoryB2C.sln”, then add new MVC ASP.NET Web application, the selected template for the project will be “MVC”, and do not forget to change the “Authentication Mode” to “No Authentication” check the image below:

Azure B2C Web Mvc Template

Once the project has been created, click on it’s properties and set “SSL Enabled” to “True”, copy the “SSL URL” value and right lick on project, select “Properties”, then select the “Web” tab from the left side and paste the “SSL URL” value in the “Project Url” text field and click “Save”. We need to allow https scheme locally once we debug the application. Check the image below:

MvcWebSSLEnable

Step 2: Install the needed NuGet Packages to Configure the MVC App

We need to add bunch of NuGet packages, so Open NuGet Package Manager Console and install the below packages:

Install-Package Microsoft.Owin.Security.OpenIdConnect -Version 3.0.1
Install-Package Microsoft.Owin.Security.Cookies -Version 3.0.1
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.1
Update-package Microsoft.IdentityModel.Protocol.Extensions

The package “Microsoft.Owin.Security.OpenIdConnect” contains the middleware used to protect web apps with OpenId Connect, this package contains the logic for the heavy lifting happens when our MVC App will talk with Azure B2C tenant to request tokens and validate them.

The package “Microsoft.IdentityModel.Protocol.Extension” contains classes which represent OpenID Connect constants and messages, lastly the package “Microsoft.Owin.Security.Cookies” will be used to create a cookie based session after obtaining a valid token from our Azure AD B2C tenant. This cookie will be sent from the browser to the server with each subsequent request and get validate by the cookie middleware.

Step 3: Configure Web App to use Azure AD B2C tenant IDs and Policies

Now we need to modify the web.config for our MVC App  by adding the below keys, so open Web.config and add the below AppSettings keys:

<add key="ida:Tenant" value="BitofTechDemo.onmicrosoft.com" />
    <add key="ida:ClientId" value="bc348057-3c44-42fc-b4df-7ef14b926b78" />
    <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration?p={1}" />
    <add key="ida:SignUpPolicyId" value="B2C_1_Signup" />
    <add key="ida:SignInPolicyId" value="B2C_1_Signin" />
    <add key="ida:UserProfilePolicyId" value="B2C_1_Editprofile" />
    <add key="ida:RedirectUri" value="https://localhost:44315/" />
    <add key="api:OrdersApiUrl" value="https://localhost:44339/" />

The usage for the each setting has been outlined in the previous post, the only 2 new settings keys are: “ida:RedirectUri” which will be used to set the OpenID connect “redirect_uri” property The value of this URI should be registered in Azure AD B2C tenant (we will do this next), this redirect URI will be used by the OpenID Connect middleware to return token responses or failures after authentication process, as well after the sign out process. The second setting key “api:OrdersApiUrl” will be used as a base URI for our Web API.

Now let’s register the new Redirect URI in Azure B2C tenant, to do so login to Azure Portal and navigate to the App “Bit of Tech Demo App” we already registered in the previous post, then add the value “https://localhost:44315/” in the Reply URL settings as the image below, note that I already published the MVC web App to Azure App Services to the URL (https://aadb2cmvcapp.azurewebsites.net/) so I’ve included this URL too.

B2C Mvc Reply URL

Step 4: Add Owin “Startup” Class

The default MVC template comes without a “Startup” class, but we need to configure our OWIN OpenID Connect middleware at the start of our Web App, so add a new class named “Startup” and paste the code below, there is a lot of code here so jump to the next paragraph as I will do my best to explain what we have included in this class.

public class Startup
    {
        // App config settings
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        private static string aadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
        private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];

        // B2C policy identifiers
        public static string SignUpPolicyId = ConfigurationManager.AppSettings["ida:SignUpPolicyId"];
        public static string SignInPolicyId = ConfigurationManager.AppSettings["ida:SignInPolicyId"];
        public static string ProfilePolicyId = ConfigurationManager.AppSettings["ida:UserProfilePolicyId"];

        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }

        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions() );

            // Configure OpenID Connect middleware for each policy
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignUpPolicyId));
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(ProfilePolicyId));
            app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInPolicyId));
        }

        // Used for avoiding yellow-screen-of-death
        private Task AuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            if (notification.Exception.Message == "access_denied")
            {
                notification.Response.Redirect("/");
            }
            else
            {
                notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
            }

            return Task.FromResult(0);
        }

        private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
        {
            return new OpenIdConnectAuthenticationOptions
            {
                // For each policy, give OWIN the policy-specific metadata address, and
                // set the authentication type to the id of the policy
                MetadataAddress = String.Format(aadInstance, tenant, policy),
                AuthenticationType = policy,
              
                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = clientId,
                RedirectUri = redirectUri,
                PostLogoutRedirectUri = redirectUri,
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthenticationFailed = AuthenticationFailed
                },
                Scope = "openid",
                ResponseType = "id_token",

                // This piece is optional - it is used for displaying the user's name in the navigation bar.
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    SaveSigninToken = true //important to save the token in boostrapcontext
                }
            };
        }
    }

What we have implemented here is the following:

  • From line 4-12 we have read the app settings for the keys we have included in MVC App web.config where they represent Azure AD B2C tenant and policy names, note that policy names access modifiers are set to public as it will be referenced in another class.
  • Inside the method “ConfigureAuth” we have done different things as the following:
    • Line 
      app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType)
       will configure the OWIN security pipeline and inform the OpenID connect middleware that the default authentication type we will use is”Cookies”, and this means that the “Claims” encoded in the token we will receive from Azure AD B2C tenant will be stored in a Cookie (Session for the authenticated user).
    • Line 
      app.UseCookieAuthentication(new CookieAuthenticationOptions());
       will register a cookie authentication middleware instance with default options, this means that Authentication type here is equivalent to the same authentication type we set in the previous step. it will be “Cookies” too.
    • Lines 
      app.UseOpenIdConnectAuthentication
       are used to configure the OWIN security pipeline to use the authentication provider (Azure AD B2C) per policy, in our case, there will be 3 different policies we already defined.
  • The method 
    CreateOptionsFromPolicy
     will take the Policy name as input parameter and will return an object of type “OpenIdConnectAuthenticationOptions”, This object is responsible for controlling the OpenID Connect middleware. The properties we used to configure the instance of “OpenIdConnectAuthenticationOptions” as the below:
    • The
      MetadataAddress
       property will accept the address of the discovery document endpoint for our Azure AD B2C tenant per policy, so for example, the discovery endpoint for policy “B2C_1_Signup” will be “https://login.microsoftonline.com/BitofTechDemo.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_Signup”. This discovery document will be used to get information from Azure AD B2C on how to generate authentication requests and validated incoming token responses.
    • The 
      AuthenticationType
       property will inform the middleware that authentication operation used is the policies we already defined, so for example if you defined a forth policy and you didn’t register it with the OpenID connect middleware, the tokens issues by this policy will be rejected.
    • The 
      ClientId
       property will tell Azure AD B2C which ID to use to match the requests originating from the Web App. This will represent the Azure AD B2C tenant we defined earlier in the previous posts.
    • The 
      RedirectUri
       property will inform the Azure AD B2C where your app wants the requested token response to be returned to, the value of this URL should be registered previously in the “ReplyURLs” values in Azure AD B2C App we defined earlier.
    • The 
      PostLogoutRedirectUri
       property will inform Azure AD B2C where to redirect the browser after a sign out operation completed successfully.
    • The 
      Scope
       property will be used to inform our Azure AD B2C tenant that our web app needs to use “OpenId Connect” protocol for authentication.
    • The 
      ResponseType
       property will indicate what our Web App needs from Azure AD B2C tenant after this authentication process, in our case, we only need an 
      id_token
    • The 
      TokenValidationParameters
       is used to store the information needed to validate the tokens, we only need to change 2 settings here, the 
      NameClaimType
       and the 
      SaveSigninToken
       . Setting the “NameClaimType” value to “name” will allow us to read the display name of the user by calling 
      User.Identity.Name
       , and setting the “SaveSigninToken” to “true” will allow us to save the token we received from the authentication process in the claims created (Inside the session cookie), this will be useful to retrieve the token from the claims when we want to call the Web API. Keep in mind that the cookie size will get larger as we are storing the token inside it.
    • Lastly, the property 
      Notifications
       will allow us to inject our custom code during certain phases of the authentication process, the phase we are interested in here is the 
      AuthenticationFailed
       phase, in this phase we want to redirect the user to the root directory of the Web App in case he/she clicked cancel on the sign on or sign in forms, and we need to redirect to the error view if we received any other exception during the authentication process.

This was the most complicated part in configuring our Web App to use our Azure AD B2C tenant. Now the next steps should be simpler and we will modify some views and add some new actions to issue requests to our Web API and call the Azure AD B2C polices.

Step 5: Call the Azure B2C Polices

Now we need to configure out Web App to invoke the policies we created, to do so we need to add a new controller named “AccountController”, so add it and paste the code below:

public class AccountController : Controller
    {
        public void SignIn()
        {
            if (!Request.IsAuthenticated)
            {
                // To execute a policy, you simply need to trigger an OWIN challenge.
                // You can indicate which policy to use by specifying the policy id as the AuthenticationType
                HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties() { RedirectUri = "/" }, Startup.SignInPolicyId);
            }
        }

        public void SignUp()
        {
            if (!Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties() { RedirectUri = "/" }, Startup.SignUpPolicyId);
            }
        }

        public void Profile()
        {
            if (Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties() { RedirectUri = "/" }, Startup.ProfilePolicyId);
            }
        }

        public void SignOut()
        {
            // To sign out the user, you should issue an OpenIDConnect sign out request
            if (Request.IsAuthenticated)
            {
                IEnumerable<AuthenticationDescription> authTypes = HttpContext.GetOwinContext().Authentication.GetAuthenticationTypes();
                HttpContext.GetOwinContext().Authentication.SignOut(authTypes.Select(t => t.AuthenticationType).ToArray());
            }
        }
    }

What we have implemented here is simple, and it is the same for actions 

SignIn
 , 
SignUp
 , and 
Profile
 , what we have done is a call to the 
Challenge
 method and specify the related Policy name for each action.

The “Challenge” method in the OWIN pipeline accepts an instance of the object

AuthenticationProperties()
  which is used to set the settings of the action we want to do (Sign in, Sign up, Edit Profile). We only set the “RedirectUri” here to the root path of our Web App, taking into consideration that this “RedirectUri” has nothing to do with the “RedirectUri” we have defined in Azure AD B2C. This can be a different URI where you want the browser to redirect the user only after a successful operation takes place.

Regarding the 

SignOut
 action, we need to Signout the user from different places, one by removing the app local session we created using the “Cookies” authentication and the other one by informing the OpenID connect middleware to send a Sign out request message to our Azure AD B2C tenant so the user is signed out from there too, that’s why we are retrieving all the Auth types available for our Web App and then we pass those different authentication types to the the “SignOut” method.

Now let’s add a partial view which renders the links to call those actions, so add a new partial view named “_LoginPartial.cshtml” under the “Shared” folder and paste the code below:

@if (Request.IsAuthenticated)
{
    <text>
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a id="profile-link">@User.Identity.Name</a>
                <div id="profile-options" class="nav navbar-nav navbar-right">
                    <ul class="profile-links">
                        <li class="profile-link">
                            @Html.ActionLink("Edit Profile", "Profile", "Account")
                        </li>
                    </ul>
                </div>
            </li>
            <li>
                @Html.ActionLink("Sign out", "SignOut", "Account")
            </li>
        </ul>
    </text>
}
else
{
    <ul class="nav navbar-nav navbar-right">
        <li>@Html.ActionLink("Sign up", "SignUp", "Account", routeValues: null, htmlAttributes: new { id = "signUpLink" })</li>
        <li>@Html.ActionLink("Sign in", "SignIn", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
    </ul>
}

Notice that part of partial view will be rendered only if the user is authenticated and notice how we are displaying the user “Display Name” from the claim named “name” by only calling 

@User.Identity.Name

Now we need to reference this partial view in the “_Layout.cshtml” view, we need just to replace the last Div in the body section with the below section:

<div class="navbar-collapse collapse">
	<ul class="nav navbar-nav">
		<li>@Html.ActionLink("Home", "Index", "Home")</li>
		<li>@Html.ActionLink("Orders List", "Index", "Orders")</li>
	</ul>
	@Html.Partial("_LoginPartial")
</div>

Step 6: Call the Web API from the MVC App

Now we want to add actions to start invoking the protected API we’ve created by passing the token obtained from Azure AD B2C tenant in the “Authorization” header for each protected request. We will add support for creating a new order and listing all the orders related to the authenticated user. If you recall from the previous post, we will depend on the claim named “objectidentifer” to read the User ID value encoded in the token as a claim.

To do so we will add a new controller named “OrdersController” under folder “Controllers” and will add 2 actions methods named “Index” and “Create”, add the file and paste the code below:

[Authorize]
    public class OrdersController : Controller
    {
        private static string serviceUrl = ConfigurationManager.AppSettings["api:OrdersApiUrl"];

        // GET: Orders
        public async Task<ActionResult> Index()
        {
            try
            {

                var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;

                HttpClient client = new HttpClient();

                client.BaseAddress = new Uri(serviceUrl);

                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bootstrapContext.Token);

                HttpResponseMessage response = await client.GetAsync("api/orders");

                if (response.IsSuccessStatusCode)
                {

                    var orders = await response.Content.ReadAsAsync<List<OrderModel>>();

                    return View(orders);
                }
                else
                {
                    // If the call failed with access denied, show the user an error indicating they might need to sign-in again.
                    if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                    {
                        return new RedirectResult("/Error?message=Error: " + response.ReasonPhrase + " You might need to sign in again.");
                    }
                }

                return new RedirectResult("/Error?message=An Error Occurred Reading Orders List: " + response.StatusCode);
            }
            catch (Exception ex)
            {
                return new RedirectResult("/Error?message=An Error Occurred Reading Orders List: " + ex.Message);
            }
        }

        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public async Task<ActionResult> Create([Bind(Include = "ShipperName,ShipperCity")]OrderModel order)
        {

            try
            {
                var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;

                HttpClient client = new HttpClient();

                client.BaseAddress = new Uri(serviceUrl);

                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bootstrapContext.Token);

                HttpResponseMessage response = await client.PostAsJsonAsync("api/orders", order);

                if (response.IsSuccessStatusCode)
                {
                    return RedirectToAction("Index");
                }
                else
                {
                    // If the call failed with access denied, show the user an error indicating they might need to sign-in again.
                    if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                    {
                        return new RedirectResult("/Error?message=Error: " + response.ReasonPhrase + " You might need to sign in again.");
                    }
                }

                return new RedirectResult("/Error?message=An Error Occurred Creating Order: " + response.StatusCode);
            }
            catch (Exception ex)
            {
                return new RedirectResult("/Error?message=An Error Occurred Creating Order: " + ex.Message);
            }

        }

    }

    public class OrderModel
    {
        public string OrderID { get; set; }
        [Display(Name = "Shipper")]
        public string ShipperName { get; set; }
        [Display(Name = "Shipper City")]
        public string ShipperCity { get; set; }
        public DateTimeOffset TS { get; set; }
    }

What we have implemented here is the following:

  • We have added an 
    [Authorize]
     attribute on the controller so any unauthenticated (anonymous) request (Session cookie doesn’t exist) to any of the actions in this controller will result into a redirect to the Sign in policy we have configured.
  • Notice how we are reading the 
    BootstrapContext
     from the current “ClaimsPrincipal” object, this context will contain a property named “Token” which we will send in the “Authorization” header for the Web API. Note that if you forgot to set the property “SaveSigninToken” of the “TokenValidationParameters” to “true” then this will return “null”.
  • We are using HTTP Client to craft the requests and call the Web API endpoints we defined earlier. There is no need to pay attention to the User ID property in the MVC App as this property is encoded in the token itself, and the Web API will take the responsibility to decode it and store it in the Azure table storage along with order information.

Step 7: Add views for the Orders Controller

I will not dive into details here, as you know we need to add 2 views to support rendering the list of orders and creating a new order, for sake of completeness I will paste the cshtml for each view, so open a new folder named “Orders” under “Views” folder, then add 2 new views named “Index.cshtml” and “Create.cshtml” and paste the code as the below:

@model IEnumerable<AADB2C.WebClientMvc.Controllers.OrderModel>
@{
    ViewBag.Title = "Orders";
}
<h2>Orders</h2>
<br />
<p>
    @Html.ActionLink("Create New", "Create")
</p>

<table class="table table-bordered table-striped table-hover table-condensed" style="table-layout: auto">
    <thead>
        <tr>
            <td>Order Id</td>
            <td>Shipper</td>
            <td>Shipper City</td>
            <td>Date</td>
        </tr>
    </thead>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.OrderID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ShipperName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ShipperCity)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.TS)
            </td>
        </tr>
    }
</table>

@model AADB2C.WebClientMvc.Controllers.OrderModel
@{
    ViewBag.Title = "New Order";
}
<h2>Create Order</h2>
@using (Html.BeginForm())
{
    <div class="form-horizontal">
        <hr />

        <div class="form-group">
            @Html.LabelFor(model => model.ShipperName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ShipperName, new { htmlAttributes = new { @class = "form-control" } })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ShipperCity, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ShipperCity, new { htmlAttributes = new { @class = "form-control" } })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save Order" class="btn btn-default" />
            </div>
        </div>
    </div>

    <div>
        @Html.ActionLink("Back to Orders", "Index")
    </div>
}

Step 8: Lastly, let’s test out the complete flow

To test this out the user will click on “Orders List” link from the top navigation menu, then he will be redirected to the Azure AD B2C tenant where s/he can enter the app local credentials, if the crednetials provided are valid then a successful authentication will take place and a token will be obtained and stored in the claims identity for the authenticated user, then the orders view are displayed the token is sent in the authorization header to get all orders for this user. It should be something as the animated image below:

Azure AD B2C animation

That’s it for now folks, I hope you find it useful 🙂 In the next post, I will cover how to integrate MSAL with Azure AD B2C and use it in a desktop application. If you find the post useful; then do not forget to share it 🙂

The Source code for this tutorial is available on GitHub.

The MVC Web App has been published on Azure App Services, so feel free to try it out using the Base URL (https://aadb2cmvcapp.azurewebsites.net/)

Follow me on Twitter @tjoudeh

Resources

The post Integrate Azure AD B2C with ASP.NET MVC Web App – Part 3 appeared first on Bit of Technology.

Viewing all 37 articles
Browse latest View live