The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.
Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by animeshli1987, 2017-06-16 13:11:33

asp-net-web-api-2-recipes

asp-net-web-api-2-recipes

Chapter 10 ■ Securing an ASP.NET Web API Service

The other side of the communication process (the server) can recalculate the MAC using the provided fields and
the symmetric key, and verify the validity of the incoming request.

In general, HMAC-based authentications mechanisms, such as Hawk, are often used in machine-to-machine
APIs, such as the interaction between your application’s backend with Amazon Web Services or between different
systems that are part of your enterprise application landscape.

■■Tip  You can read more about Hawk at the project’s official Github repository at
https://github.com/hueniverse/hawk.

The Code

Listing 10-17 shows an example of configuring an ASP.NET Web API service (in this case a self-hosted one) to use
Hawk. Since HawkMessageHandler is a subclass of DelegatingHandler, it has to be added to the MessageHandlers
collection on your HttpConfiguration. In this example, the server is configured to use a predefined key and SHA256
algorithm. The time skew is the second parameter passed to HawkMessageHandler and it defines the length of the
window that the timestamp between the client and the server can drift apart.

Listing 10-17.  Web API Self-host Using HawkNet

const string address = "http://localhost:925/";

var config = new HttpSelfHostConfiguration(address);
config.MapHttpAttributeRoutes();
var handler = new HawkMessageHandler(

async id => new HawkCredential
{

Id = id,
Key = "abcdefghijkl",
Algorithm = "sha256",
User = "filip"
}, 30, true);

config.MessageHandlers.Add(handler);

using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.ReadLine();
}

HawkMessageHandler will create a new ClaimsPrincipal and a ClaimsIdentity, set to “Hawk”, and inject it into
the Web API pipeline so that you can access it all across the ASP.NET Web API service. In the example from Listing 10-17,
the ClaimTypes.Name will be set to “filip” since the username is explicitly set as HawkCredential.
It is now enough for you to decorate the relevant controllers/action in your Web API with AuthorizeAttribute to
prevent access of unauthorized or anonymous clients.
An example of calling the Hawk-protected endpoint using HttpClient is shown in Listing 10-18. On this side
of the equation, HawkNet also provides some helpers: HawkClientMessageHandler can be used together with

302

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

HttpClient to simplify its configuration. It will deal with all the Hawk-related responsibilities, such as converting
a HawkCredential instance into relevant Authorization header value, introducing a timespan value, generating a
nonce, calculating MAC, and so on.

Listing 10-18.  Calling a Hawk-Protected Web API Endpoint from HttpClient

var credential = new HawkCredential
{

Id = "this-is-my-id",
Key = "abcdefghijkl",
Algorithm = "sha256",
User = "filip"
};

var clientHandler = new HawkClientMessageHandler(new HttpClientHandler(), credential, ts: DateTime.Now);
var client = new HttpClient(clientHandler);
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:925/test");
var response = await client.SendAsync(request);
//process response

Of course, calling the endpoint will work from any client, not just HttpClient, as long as the Authorization
header is properly set. The raw HTTP request from your example should look like this:

GET http://localhost:925/test HTTP/1.1
Host: localhost:925
Hawk id="this-is-my-id", ts="1401189959", nonce="MWPwhT", mac="vAJD3BDSYUVUg/C4u+3g2d1oJ6eJs8QRxTrf
gHhCRR8=", ext=""

■■Tip The GitHub repository for HawkNet is full of many detailed, interesting samples at
https://github.com/pcibraro/hawknet/.

10-6. Use OAuth 2.0 with ASP.NET Web API

Problem

You would like to use your ASP.NET Web API application as an OAuth 2.0 server, as well as enable OAuth bearer
authentication for consuming OAuth bearer tokens.

Solution

Project Katana provides the middleware necessary for running an OAuth2 server as part of the Microsoft.Owin.
Security.OAuth NuGet package. To get up and running, you need to use two primary extension methods as part of
your Katana configuration:

• UseOAuthBearerAuthentication, to enable OAuth bearer token support (token consumption)

• UseOAuthAuthorizationServer, to enable your Web API OWIN-hosted application to act as
an OAuth server, performing the credentials validation and granting a bearer token allowing
access to specific resources

303

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

How It Works

The OAuth 2.0 Authorization Framework is defined in RFC 6749, and succeeds OAuth 1.0 (RFC 5849).

The OAuth 2.0 authorization framework enables a third-party application to obtain limited access
to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the third-party application to
obtain access on its own behalf.

Internet Engineering Task Force (IETF), RFC 6749,
http://tools.ietf.org/html/rfc6749

OAuth 2.0 supports two primary authentication variants: three-legged (originally developed as part of OAuth 1.0)
and two-legged. In a three-legged approach, a resource owner (a user), can assure a third party client (for example
a mobile application) about his identity through a content provider (OAuth server) without having to share any
credentials with that third-party client. A two-legged approach is a typical client-server approach, where a client can
directly authenticate the user with the content provider.

Configuration of the Katana-based OAuth Authorization Server is primarily done through the
IOAuthAuthorizationServerProvider and OAuthAuthorizationServerOptions classes.

An outline of OAuthAuthorizationServerOptions is shown in Listing 10-19. It extends the abstract
AuthenticationOptions from Microsoft.Owin.Security and is used to set the core server options such as enforcing
HTTPS, error detail level, token expiry, or endpoint paths. You can also use it to control the security of data contained
in the access tokens and authorization codes. Out-of-the-box the security is host-specific; System.Web will use
machine key data protection, while HttpListener will rely on the data protection application programming
interface (DPAPI).

Listing 10-19.  Outline of OAuthAuthorizationServerOptions

public class OAuthAuthorizationServerOptions : AuthenticationOptions
{

public OAuthAuthorizationServerOptions()
: base(OAuthDefaults.AuthenticationType)

{
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(5);
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20);
SystemClock = new SystemClock();

}


public PathString AuthorizeEndpointPath { get; set; }


public PathString TokenEndpointPath { get; set; }


public IOAuthAuthorizationServerProvider Provider { get; set; }


public ISecureDataFormat<AuthenticationTicket> AuthorizationCodeFormat { get; set; }


public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; set; }


public ISecureDataFormat<AuthenticationTicket> RefreshTokenFormat { get; set; }


public TimeSpan AuthorizationCodeExpireTimeSpan { get; set; }


304

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

public TimeSpan AccessTokenExpireTimeSpan { get; set; }


public IAuthenticationTokenProvider AuthorizationCodeProvider { get; set; }


public IAuthenticationTokenProvider AccessTokenProvider { get; set; }


public IAuthenticationTokenProvider RefreshTokenProvider { get; set; }


public bool ApplicationCanDisplayErrors { get; set; }


public ISystemClock SystemClock { get; set; }


public bool AllowInsecureHttp { get; set; }
}


IOAuthAuthorizationServerProvider is responsible for processing events raised by the authorization
server. Katana ships with a default implementation of IOAuthAuthorizationServerProvider called
OAuthAuthorizationServerProvider, which you can see in Listing 10-20. It is a very convenient starting point for
configuring the authorization server, as it allows you to either attach individual event handlers as Funcs or to inherit
from the class and override the relevant method directly.

Listing 10-20.  Outline of OAuthAuthorizationServerProvider

public class OAuthAuthorizationServerProvider : IOAuthAuthorizationServerProvider
{

public OAuthAuthorizationServerProvider();
public Func<OAuthMatchEndpointContext, Task> OnMatchEndpoint { get; set; }
public Func<OAuthValidateClientRedirectUriContext, Task> OnValidateClientRedirectUri
{ get; set; }

public Func<OAuthValidateClientAuthenticationContext, Task> OnValidateClientAuthentication
{ get; set; }
public Func<OAuthValidateAuthorizeRequestContext, Task> OnValidateAuthorizeRequest { get; set; }
public Func<OAuthValidateTokenRequestContext, Task> OnValidateTokenRequest { get; set; }
public Func<OAuthGrantAuthorizationCodeContext, Task> OnGrantAuthorizationCode { get; set; }
public Func<OAuthGrantResourceOwnerCredentialsContext, Task> OnGrantResourceOwnerCredentials
{ get; set; }
public Func<OAuthGrantClientCredentialsContext, Task> OnGrantClientCredentials { get; set; }
public Func<OAuthGrantRefreshTokenContext, Task> OnGrantRefreshToken { get; set; }
public Func<OAuthGrantCustomExtensionContext, Task> OnGrantCustomExtension { get; set; }
public Func<OAuthAuthorizeEndpointContext, Task> OnAuthorizeEndpoint { get; set; }
public Func<OAuthTokenEndpointContext, Task> OnTokenEndpoint { get; set; }
public virtual Task MatchEndpoint(OAuthMatchEndpointContext context);
public virtual Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context);
public virtual Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext
context);
public virtual Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context);
public virtual Task ValidateTokenRequest(OAuthValidateTokenRequestContext context);
public virtual Task GrantAuthorizationCode(OAuthGrantAuthorizationCodeContext context);
public virtual Task GrantRefreshToken(OAuthGrantRefreshTokenContext context);

305

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

public virtual Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext
context);
public virtual Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
public virtual Task GrantCustomExtension(OAuthGrantCustomExtensionContext context);
public virtual Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context);
public virtual Task TokenEndpoint(OAuthTokenEndpointContext context);
}


THE DEPTHS OF OAUTH

While OAuth 2.0 aims to simplify some of the concepts of OAuth 1.0, it is still a very broad and complex
authorization framework. It is far beyond the scope and format of this book to go into details of OAuth; in this
particular recipe I merely scratch the surface.

Why? There is a whole complicated security world of dealing with token providers, token types, refreshing tokens,
redirect URI validations, authorization code grants, and a lot more—which you will definitely have to deal with in
more complex OAuth usage scenarios.

To help you get going, the ASP.NET team provides an excellent, free-to-use (Apache 2 licensed), end-to-end
sample of OAuth2 with OWIN and ASP.NET Web API at
http://code.msdn.microsoft.com/OWIN-OAuth-20-Authorization-ba2b8783.

In addition to that, Badrinarayanan Lakshmiraghavan dedicated a couple of chapters in his Pro ASP.NET Web
API Security book (www.apress.com/microsoft/asp-net/9781430257820) exclusively to ASP.NET Web API and
OAuth 2.0 integration.

The Code

When working with three-legged OAuth, the resource server (consuming tokens and exposing data based on them)
and the authorization server (issues access tokens) are separate from each other, often controlled by different parties
too (i.e. a sing Twitter as authorization server).

However, in simpler scenarios, resource and authorization servers can be combined into what’s known as an
“embedded authorization server.” Listing 10-21 shows a Katana Startup class, configured to issue the tokens, use the
bearer tokens for authentication and host ASP.NET Web API at the same time.

Listing 10-21.  Katana Startup Configured as OAuth Server and a Web API Server

public class Startup
{

public void Configuration(IAppBuilder app)
{

var oauthProvider = new OAuthAuthorizationServerProvider
{

OnGrantResourceOwnerCredentials = async context =>
{

//sample! validate credentials here
if (context.UserName == "filip" && context.Password == "test")

306

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

{
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim("user", context.UserName));
context.Validated(claimsIdentity);
return;

}
context.Rejected();
},
OnValidateClientAuthentication = async context =>
{
string clientId;
string clientSecret;

//sample! validate clientId and secret here
if (context.TryGetBasicCredentials(out clientId, out clientSecret))
{

if (clientId == "filipClient" && clientSecret == "secretKey")
{

context.Validated();
}
}
}
};

var oauthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true, //this is set to avoid having to setup TLS in the demo
TokenEndpointPath = new PathString("/accesstoken"),
Provider = oauthProvider
};

app.UseOAuthAuthorizationServer(oauthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
}
In the sample, you attach two event handlers to the OAuthAuthorizationServerProvider. First is
OnValidateClientAuthentication, which is used when requesting the access token. Inside that event handler,
client ID and secret are extracted from the Authorization header (basic authentication) and validated. Then
OnGrantResourceOwnerCredentials is used to validate the credentials of the resource owner and create a concrete
ClaimsIdentity based on that. The credentials are passed in as regular application/x-www-form-urlencoded
form data.


307

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

After the authorization server has been configured, you can proceed to configure the resource server, which is
done by calling the UseOAuthBearerAuthentication method and passing in OAuthBearerAuthenticationOptions.
Similarly to the authorization server, it can also be customized to use specific token providers or have specific event
handlers attached as Funcs (i.e. to handle challenge or token validation). However, for the example in Listing 10-21,
the default settings are sufficient.

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());


This means that connecting clients should use an Authorization header with the type Bearer, and pass in
the access token value as the rest of the header. Please note that you absolutely have to apply HTTPS (TLS or SSL)
yourself!

Now that all the pieces are in place, you can start calling and interacting with the service over the network. Since
the sample from Listing 10-21 contained a hardcoded client/secret as filipClient and secretKey, and username/
password as filip:test, these are exactly the parameters you’ll need to use when requesting the token and then
accessing the protected resource. Listing 10-22 shows this process done from .NET using HttpClient.

Listing 10-22.  Accessing Web API With Embedded OAuth 2.0 Server from HttpClient

var client = new HttpClient();
var authorizationHeader =
Convert.ToBase64String(Encoding.UTF8.GetBytes("filipClient:secretKey"));

//client and secret should be sent using Basic Authentication
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
authorizationHeader);

var form = new Dictionary<string, string>
{

{"grant_type", "password"},
{"username", "filip"},
{"password", "test"}
};

var tokenResponse = await client.PostAsync("http://localhost:925/accesstoken",
new FormUrlEncodedContent(form));

var token = await tokenResponse.Content.ReadAsAsync<Token>(new[] {new JsonMediaTypeFormatter()});

//now reset Authorization header to a Bearer token
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.
AccessToken);

//this is the actual response from a secured Web API resource
var authorizedResponse = client.GetAsync("http://localhost:925/api/test");

The code should be quite easy to follow. First, a basic authentication header is set based on the client_id
and secret; this needs to have base64 format. A prepared request is then sent to the /accesstoken endpoint,
along with the form data composed of username, password, and grant_type (password). In response, an
access token is returned (by default valid for 20 minutes, since you do not specify a custom TimeSpan in the
OAuthAuthorizationServerOptions), which is then used for the next request in the Bearer scheme.

308

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

This is how you are allowed to access the protected Web API resource. Both the sample Web API resource
and the Token helper class, which is used to deserialize the responses containing the access token, are shown in
Listing 10-23. Since all OAuth configuration happens at OWIN level in Web API, it’s enough to just decorate a
resource with AuthorizeAttribute.

Listing 10-23.  Token Helper Class and a Sample Web API Resource

public class Token
{

[JsonProperty("access_token")]
public string AccessToken { get; set; }

[JsonProperty("token_type")]
public string TokenType { get; set; }

[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }

[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}

[Authorize]
public class TestController : ApiController
{
[Route("test")]
public HttpResponseMessage Get()
{

return Request.CreateResponse(HttpStatusCode.OK, "hello from a secured resource!");
}
}

Even though the sample here used HttpClient, the whole process of accessing your secured Web API resource
through an embedded OAuth 2.0 server is obviously compatible with any HTTP-capable client.

■■Tip  For more sophisticated scenarios, it is definitely recommended to use an existing OAuth2 client library, such
as Thinktecture.IdentityModel.Client, rather than go through the cumbersome process of manually dealing
with HttpClient.

10-7. Safely Access Current IPrincipal

Problem

You would like to access the current IPrincipal object from various components of your Web API pipeline, in a safe
and unit test-friendly way.

309

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

Solution

The recommended way of accessing the current IPrincipal is through the RequestContext object, which is
available from every instance of HttpRequestMessage. This is contrary to the traditional approach of using Thread.
CurrentPrincipal in self-hosted or HttpContext.Current.User in web-hosted scenarios.

var requestContext = request.GetRequestContext();
//use requestContext.Principal


There are a number of benefits here. When doing asynchronous work, the thread context can easily switch and
there is no guarantee that using Thread.CurrentPrincipal will synchronize correctly. Moreover, the static nature
of Thread.CurrentPrincipal or HttpContext.Current.User introduces unnecessary complexity when it comes to
maintaining and testing your code.

How It Works

HttpRequestContext was introduced into ASP.NET Web API 2 to provide a more organized approach to the request-
specific data and metadata that was normally stored inside of the request Properties dictionary (i.e. flag whether the
request is local), in static objects (i.e. IPrincipal on the Thread.CurrentPrincipal), or was disconnected from the
request instance (i.e. UrlHelper) at all.

HttpRequestContext, shown in Listing 10-24, is a POCO and does not provide any behavior. All of its properties
are explicitly hydrated at various stages of the Web API pipeline. The comments used in the listing come directly from
the ASP.NET Web API source, and have been left here as they provide a good insight into the use of each property.

Listing 10-24.  Definition of HttpRequestContext

public class HttpRequestContext
{

public HttpRequestContext()
{

// This is constructor is available to allow placing breakpoints on //construction.
}

/// <summary>Gets or sets the client certificate.</summary>
public virtual X509Certificate2 ClientCertificate { get; set; }

/// <summary>Gets or sets the configuration.</summary>
public virtual HttpConfiguration Configuration { get; set; }

/// <summary>
/// Gets or sets a value indicating whether error details, such as //exception messages and
stack traces,
/// should be included in the response for this request.
/// </summary>
public virtual bool IncludeErrorDetail { get; set; }

/// <summary>Gets or sets a value indicating whether the request //originates from a local
address.</summary>
public virtual bool IsLocal { get; set; }


310

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

/// <summary>Gets or sets the principal.</summary>
public virtual IPrincipal Principal { get; set; }

/// <summary>Gets or sets the route data.</summary>
public virtual IHttpRouteData RouteData { get; set; }

/// <summary>Gets or sets the factory used to generate URLs to other APIs.</summary>
public virtual UrlHelper Url { get; set; }

/// <summary>Gets or sets the virtual path root.</summary>
public virtual string VirtualPathRoot { get; set; }
}

From the developer’s standpoint, the most important security information about HttpRequestContext is
that the IPrincipal is guaranteed to flow across the threads in case context switching happens, such as when an
asynchronous operation starts on one thread and completes on another.
An instance of the HttpRequestContext is actually held inside the Properties dictionary of the
HttpRequestMessage, under HttpPropertyKeys.RequestContextKey key. As a consequence, you will not be
surprised to hear that the GetRequestContext method, used to obtain the HttpRequestContext from the current
request, is simply an extension method that retrieves the context instance from the request’s Properties. A similar
SetRequestContext extension method is publicly available too, and is used by the framework to initially set the
context on the request. Additionally, it’s perfect to be used in unit testing scenarios where you might want to mock
some of the objects carried by the HttpRequestContext, like in your specific case, an IPrincipal.
Additionally, if you are working with IAuthenticationFilter in the AuthenticateAsync method, you will
have access to HttpAuthenticationContext (shown in Listing 10-25). It also exposes an IPrincipal, through a
Principal property. When building a custom authentication solution using IAuthenticationFilter, you only
need to set the Principal on the HttpAuthenticationContext; the framework will ensure that it gets synced to the
HttpRequestContext automatically.

Listing 10-25.  Overview of the HttpAuthenticationContext

public class HttpAuthenticationContext
{

public HttpAuthenticationContext(HttpActionContext actionContext, IPrincipal principal);


public HttpActionContext ActionContext { get; private set; }
public IPrincipal Principal { get; set; }
public IHttpActionResult ErrorResult { get; set; }
public HttpRequestMessage Request {get; }
}

Finally, the base ApiController exposes a User property, which also returns the current IPrincipal, so
whenever you are working in the controller, you can use that to interact with the current IPrincipal. However, under
the hood the property is simply a shortcut to HttpRequestContext too, as shown in Listing 10-26.

Listing 10-26.  User Property on the ApiController

public IPrincipal User
{

get { return RequestContext.Principal; }
set { RequestContext.Principal = value; }
}

311

www.it-ebooks.info

Chapter 10 ■ Securing an ASP.NET Web API Service

The Code

Listing 10-27 shows accessing the HttpRequestContext from a simple Basic authentication MessageHandler. The code
extracts user name and password from the Authorization header and creates a new ClaimsPrincipal based on that.
Then, the principal object is set on the RequestContext, which is enough to complete the authentication process. The
big advantage of working with IPrincipal this way is that the message handler can now be easily unit tested because
RequestContext can be stubbed.

Listing 10-27.  A Sample Message Handler, Setting IPrincipal on the HttpRequestContext

public class BasicAuthHandler : DelegatingHandler
{

private const string BasicAuthResponseHeaderValue = "Basic";
private const string Realm = "Apress";

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

bool identified = false;
if (request.Headers.Authorization != null && string.Equals(request.Headers.Authorization.
Scheme, BasicAuthResponseHeaderValue, StringComparison.CurrentCultureIgnoreCase))
{

var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(request.Headers.
Authorization.Parameter));
var user = credentials.Split(':')[0].Trim();
var pwd = credentials.Split(':')[1].Trim();

//validate username and password here and set identified flag
//omitted for brevity

if (identified)
{

var identity = new ClaimsIdentity(new[] {new Claim(ClaimTypes.Name, user)},
BasicAuthResponseHeaderValue);
request.GetRequestContext().Principal = new ClaimsPrincipal(new[] { identity });
}
}

if (!identified)
{
var unauthorizedResponse = request.CreateResponse(HttpStatusCode.Unauthorized);
unauthorizedResponse.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue(BasicAuth
ResponseHeaderValue, Realm));
return Task.FromResult(unauthorizedResponse);
}

return base.SendAsync(request, cancellationToken);
}
}


312

www.it-ebooks.info














































































Click to View FlipBook Version