Fletch
Fletch

Reputation: 163

Extend functionality of Azure Mobile Services using ASP.NET Identity

I have a .Net Mobile Services back end (i.e. not the JavaScript one) which out of the box supports authentication with the common Identity Providers (facebook, twitter, etc) through the windows azure portal. However I would like users to be able to create their own username/password accounts as they can do with the ASP.NET Web Api implementation of ASP.NET Identity (using AccountController).

The question is if this is possible and if so what is the best way of achieving it?

My first thought was to just copy the appropriate classes (AccountController, Startup.Auth, ApplicationOAuthProvider, etc) from a template ASP.NET MVC Web Api project and add a reference to Microsoft.AspNet.Identity.EntityFramework and System.Web.MVC but I don't know what impact this would have. If it worked would I have just taken control of the Authentication logic with the portal "Identity" no longer having any effect?

The other option is to simply start with a Web Api project and add the Mobile Services functionality to that instead (Although I couldn't see how to create a Web Api project without MVC but that is a different question).

Thanks for any help.

UPDATE 11 April 2014

In the end we decided to manage our own username and passwords and generate a JWT token so that the client could use the standard IMobileServiceClient. To do this we used two resources. The first was from the joy of code:

http://www.thejoyofcode.com/Exploring_custom_identity_in_Mobile_Services_Day_12_.aspx

and the second was from content master:

http://www.contentmaster.com/azure/creating-a-jwt-token-to-access-windows-azure-mobile-services/

Although we made some small changes to the code as per this Mobile Services team blog post:

[Don't have enough reputation points to add a third link so just google "changes-in-the-azure-mobile-services-jwt-token"]

So here is the code if useful. (it might be better to write an implementation using JwtSecurityTokenHandler but this works for us)

 public static string GetSecurityToken(TimeSpan periodBeforeExpires, string aud, string userId, string masterKey)
    {
        var now = DateTime.UtcNow;
        var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        var payload = new
                      {
                          exp = (int)now.Add(periodBeforeExpires).Subtract(utc0).TotalSeconds,
                          iss = "urn:microsoft:windows-azure:zumo",
                          ver = 2,
                          aud = "urn:microsoft:windows-azure:zumo",
                          uid = userId
                      };

        var keyBytes = Encoding.UTF8.GetBytes(masterKey + "JWTSig");
        var segments = new List<string>();

        //kid changed to a string
        var header = new { alg = "HS256", typ = "JWT", kid = "0" };
        byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
        byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
        segments.Add(Base64UrlEncode(headerBytes));
        segments.Add(Base64UrlEncode(payloadBytes));
        var stringToSign = string.Join(".", segments.ToArray());
        var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
        SHA256Managed hash = new SHA256Managed();
        byte[] signingBytes = hash.ComputeHash(keyBytes);
        var sha = new HMACSHA256(signingBytes);
        byte[] signature = sha.ComputeHash(bytesToSign);
        segments.Add(Base64UrlEncode(signature));
        return string.Join(".", segments.ToArray());
    }

  // from JWT spec
    private static string Base64UrlEncode(byte[] input)
    {
        var output = Convert.ToBase64String(input);
        output = output.Split('=')[0]; // Remove any trailing '='s
        output = output.Replace('+', '-'); // 62nd char of encoding
        output = output.Replace('/', '_'); // 63rd char of encoding
        return output;
    }

Upvotes: 2

Views: 1191

Answers (1)

Henrik Frystyk Nielsen
Henrik Frystyk Nielsen

Reputation: 3092

This is possible but not quite as simple as we would like (we have a bug on improving it). In general it boils down to that you can inject things into the OWIN pipeline including auth providers.

If you are familiar with the OWIN pipeline and ASP.NET Identity Framework then here's roughly what you do:

1) Crate your own OWIN App Builder which sets up the OWIN pipeline for the .NET backend.

2) Register your App Builder with the Dependency Injection engine which will get called as part of the initialization.

Here is a gist of what it looks like (using the latest NuGets from nuget.org):

https://gist.github.com/HenrikFrystykNielsen/9835526

It won't automatically get hooked into the "login" controller we have a work item to enable this but I think it should work if you are careful.

Btw, you can find some good information from Filip W's blog: http://www.strathweb.com/2014/02/running-owin-pipeline-new-net-azure-mobile-services/

Hope this helps!

Henrik

Upvotes: 1

Related Questions