DotNetOpenAuth Provider for REST Service

I created a REST API in the scope of my ASP.NET MVC 4 web application. The API is working correctly and now I would like to secure it.

Is there a very simple example on how I can do this? I am going through the samples that come with the DotNetOpenAuth download and I completely lost it.

+3


source to share


1 answer


I had the same problem a couple of days ago. This answer is ridiculously long, maybe there is an easier way.

Personally, I don't use DNOA anymore because it is designed for self-typing (i.e. encrypted tokens) so you don't have to hit the DB with every request. A very important side effect of this is that revocation of access will not take effect immediately, but only after the token has to be updated. Also, the access tokens will get quite long (around 500 bytes).

As a first step, make sure you know what you need:


OAuth / OAuth2 looks easy at first, but it's important to understand how authorization workflows are designed. Also, their terminology can be annoying, for example "Client" refers to what I naively call a client application. This is not a user (called the "resource owner" in OAuth terms). My suggestion: read RFC 6749 . It looks boring, but it's fun to read (and you can skip half of it ...)

The key question is: Do you need 2-way OAuth or 3-legged OAuth (or both?). What types of grants do you need for support?

If you basically want to replace HTTP Basic Auth, then a simple "resource owner password credential flow" will do. The facebook / twitter type "have this app to access my profile information" is 3 digit OAuth.

There's IBM Documentation that comes with nice grant type outlines .


Now in DNOA take a look at Samples/OAuthAuthorizationServer

.

A good entry point is the file OAuthController.cs

. Note that steps Authorize

and AuthorizeResponse

are only required if you want your users to provide access to third-party applications (3-party OAuth).



In a two-legged scenario, users directly access the OAuth endpoint token

and simply request an access token. You will need such a controller in your REST application anyway.

The key to the inner workings is the class OAuth2AuthorizationServer

(not the class AuthorizationServer

). Take a look Code/OAuth2AuthorizationServer.cs

. It implements IAuthorizationServerHost

.

Half of this class deals with the data store (which you can change if you are working with a different data store), and half of them deal with encryption of access tokens. You will also need to implement IAuthorizationServerHost for your application.

Make sure you have a string in your code #define SAMPLESONLY

so it will take hardcoded.

To really resolve the request, it is helpful to write a custom one ActionFilterAttribute

. Here's some super condensed code, not a finished product:

public sealed class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
    private readonly OAuthResourceServer _authServer; 
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.Request.Headers.Authorization.Scheme == "Bearer"
            || actionContext.Request.Properties.ContainsKey("access_token"))
        {
            authenticatedUser = _authServer.VerifyOAuth2(request, required_claims);
            HttpContext.Current.User = authenticatedUser;
            Thread.CurrentPrincipal = authenticatedUser;
        }
    }
}

// See OAuthResourceServer/Code/OAuthAuthorizationManager.cs in DNOA samples
public sealed class OAuthResourceServer
{
    public IPrincipal VerifyOAuth2(HttpRequestMessage httpDetails, params string[] requiredScopes)
    {
        // for this sample where the auth server and resource server are the same site,
        // we use the same public/private key.
        using (var signing = CreateAuthorizationServerSigningServiceProvider())
        {
            using (var encrypting = CreateResourceServerEncryptionServiceProvider())
            {
                var tokenAnalyzer = new StandardAccessTokenAnalyzer(signing, encrypting);
                var resourceServer = new ResourceServer(_myUserService, tokenAnalyzer);
                return resourceServer.GetPrincipal(httpDetails, requiredScopes);
            }
        }
    }
}

      

Resource server still missing

public sealed class MyResourceServer : ResourceServer
{
    public override System.Security.Principal.IPrincipal GetPrincipal([System.Runtime.InteropServices.OptionalAttribute]
        [System.Runtime.InteropServices.DefaultParameterValueAttribute(null)]
        HttpRequestBase httpRequestInfo, params string[] requiredScopes)
    {
        AccessToken accessToken = this.GetAccessToken(httpRequestInfo, requiredScopes);
        string principalUserName = !string.IsNullOrEmpty(accessToken.User)
            ? this.ResourceOwnerPrincipalPrefix + accessToken.User
            : this.ClientPrincipalPrefix + accessToken.ClientIdentifier;
        string[] principalScope = accessToken.Scope != null ? accessToken.Scope.ToArray() : new string[0];

        // Now your own code that retrieves the user 
        // based on principalUserName from the DB:
        return myUserService.GetUser(userName);
    }
}

      

Then change the web.config so DNOA doesn't complain about lack of SSL connections in development:

<configSections>
      <sectionGroup name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection, DotNetOpenAuth">
        <section name="openid" type="DotNetOpenAuth.Configuration.OpenIdElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
        <section name="oauth" type="DotNetOpenAuth.Configuration.OAuthElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
        <sectionGroup name="oauth2" type="DotNetOpenAuth.Configuration.OAuth2SectionGroup, DotNetOpenAuth">
          <section name="authorizationServer" type="DotNetOpenAuth.Configuration.OAuth2AuthorizationServerSection, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
        </sectionGroup>
        <section name="messaging" type="DotNetOpenAuth.Configuration.MessagingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
        <section name="reporting" type="DotNetOpenAuth.Configuration.ReportingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
      </sectionGroup>    
  </configSections>
  <dotNetOpenAuth>
    <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
    <reporting enabled="true" />
    <openid>
      <provider>
        <security requireSsl="false">
        </security>
      </provider>
    </openid>
    <oauth2>
      <authorizationServer >
      </authorizationServer>
    </oauth2>
    <!-- Relaxing SSL requirements is useful for simple samples, but NOT a good idea in production. -->
    <messaging relaxSslRequirements="true">
      <untrustedWebRequest>
        <whitelistHosts>
          <!-- since this is a sample, and will often be used with localhost -->
          <add name="localhost"/>
        </whitelistHosts>
      </untrustedWebRequest>
    </messaging>
  </dotNetOpenAuth>

      

+9


source







All Articles