Starting with Open Web Interface for .NET (OWIN)

OWIN is a standard interface between .NET servers and web applications. It provides a middleware for decoupling a web server from a web application. The biggest advantage of OWIN is that we are able to host the web application anywhere, and keep the server and application completely separated.

Note

For more information on OWIN, the best place to start is with the Katana Project. Katana is a collection of projects that support OWIN with various Microsoft components.

So what does OWIN have to do with our project?

If you notice the code above we see all references to OWIN namespaces, and we register in the assembly the OwinStartup object to our Startup class. We must have at least one Startup class registered in the OwinStartup attribute. The Startup class has one function called Configuration. All Startup classes must include this function, and it must accept IAppBuilder. Additional services, such as IHostingEnvironment and ILoggerFactory may also be specified, in which case these services will be injected by the server if they are available. The Configuration specifies how the application will respond to individual HTTP requests. Finally, in our Configuration method, we will be calling the MapSignalR (an extension to the IAppBuilder object). This will define the route for clients to use to connect to your Hub/s.

Note

The route is set to the app builder pipeline at the URL /signalr by default: we can also customize this URL if required.

Our next step is to bring in some security.

Creating an authorization server using OWIN OAuth 2.0

The OAuth 2.0 framework enables a server to provide clients with limited access for HTTP services. Protected server resources can only be accessed via access tokens that expire after certain periods of time. Clients will shoot a HTTP request at a domain endpoint URL (normally /token), the server will send a response with token details (such as expiration, access token, time/date issued), and the access token will be used for a period of time with other HTTP request headers to authorize access to protected resources.

Note

Access tokens are strings denoting specified scope, lifetime, and other access attributes.

So where do we begin to set up server authorization?

Our first step is to build the logic behind granting clients access from username and password credentials.

OAuthAuthorizationServerProvider

An OAuthAuthorizationServerProvider determines how we validate user credentials using OAuthGrantResourceOwnerCredentialsContext. Its job is to simply handle the authentication of users. This item provides the context in which we handle resource grants.

Let's add a new folder called Providers, and add a new file in this folder called AuthorizationServerProvider.cs. Implement the following:

public class AuthorizationServerProvider : OAuthAuthorizationServerProvider 
    { 
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
        { 
            context.Validated(); 
        } 
  
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
        { 
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 
            string userName = null; 
  
            using (AuthenticationRepository authenticationRepository = new AuthenticationRepository()) 
            { 
                IdentityUser user = await authenticationRepository.FindUser(context.UserName, context.Password); 
  
                if (user == null) 
                { 
                    context.SetError("invalid_grant", "Incorrect user name or password"); 
                    return; 
                } 
  
                userName = user.UserName; 
            } 
  
            var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
            identity.AddClaim(new Claim("Role", "User")); 
            identity.AddClaim(new Claim("UserName", userName)); 
  
            context.Validated(identity); 
        } 
    }   

Our implementation of the OAuthAuthorizationServerProvider will override the ValidateClientAuthentication function, which simply returns whether the usercontext has been validated. We then override the GrantResourceOwnerCredentials() function, which is called when a request to the token endpoint (/token) arrives with a grant_type of password (this key is set in the request header along with the username and password). The function will simply initialize a new AuthenticationRepository to access the UserManager framework and check if the user exists; if it doesn't we return, and the context will still be invalid. If the user exists, we create a new ClaimsIdentity object with two claims, one for the role and username principles of there source owner (the user who sent the HTTP request). Finally, we then place the ClaimsIdentity object into the context.Validated() function in order to issue the access token. This ClaimsIdentity object is now the ticket that contains the claims about the resource owner (the user) associated with the access token.

Note

A ClaimsIdentity is an object that is a collection of Claim objects to represent an entity's identity. Each Claim object is simply a statement describing an identity's role, permission, or an other quality of an entity.

Use OAuthBearerAuthentication

Our next step is to add the logic behind handling bearer tokens (these are the access tokens granted by the authorization server provider). UseOAuthBearerAuthentication has the job of ensuring that only authenticated users can access your protected server resources (in our example the ChatHub). Add a new file called OAuthBearerTokenAuthenticationProvider.cs and implement the following:

public class OAuthBearerTokenAuthenticationProvider : OAuthBearerAuthenticationProvider 
    { 
        public override Task RequestToken(OAuthRequestTokenContext context) 
        { 
            string cookieToken = null; 
            string queryStringToken = null; 
            string headerToken = null; 
  
            try 
            { 
                cookieToken = context.OwinContext.Request.Cookies["BearerToken"]; 
            } 
            catch (NullReferenceException) 
            { 
                System.Diagnostics.Debug.WriteLine("The cookie does not contain the bearer token"); 
            } 
  
            try 
            { 
                queryStringToken = context.OwinContext.Request.Query["BearerToken"].ToString(); 
            } 
            catch (NullReferenceException) 
            { 
                System.Diagnostics.Debug.WriteLine("The query string does not contain the bearer token"); 
            } 
  
            try 
            { 
                headerToken = context.OwinContext.Request.Headers["BearerToken"]; 
            } 
            catch (NullReferenceException) 
            { 
                System.Diagnostics.Debug.WriteLine("The connection header does not contain the bearer token"); 
            } 
  
            if (!String.IsNullOrEmpty(cookieToken)) 
                context.Token = cookieToken; 
  
            else if (!String.IsNullOrEmpty(queryStringToken)) 
                context.Token = queryStringToken; 
  
            else if (!String.IsNullOrEmpty(headerToken)) 
                context.Token = headerToken; 
  
            return Task.FromResult<object>(null); 
        } 
    } 

Let's look at this item more closely. We are overriding the RequestToken() function to access the OAuthRequestTokenContext from every HTTP request that hits the server. Inside the OwinContext object, we can access the HTTP request that just hit the server, check through the dictionary of headers for our BearerToken, and then extract this access token and assign it to the OAuthRequestTokenContext.Token property.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.35.81