DailyStory is built on Azure so it only made sense to add support for Microsoft AppSource – when you’re a startup you look for any opportunity you can find to help people find you!
There was only one small problem though: a requirement to be listed on AppSource was to support Microsoft Identity sign in.
When I built DailyStory’s first authentication and authorization system it was built around the ASP.NET 2.0 Forms Authentication encrypted tickets. This was simple, reliable and I knew a few things about how it worked already.
When I learned the Microsoft sign in requirement for AppSource, I knew it was going to be a rewrite. So I rewrote it this past weekend.
Microsoft OWIN
The easiest path was to convert DailiyStory to use Microsoft’s OWIN middleware and support both OpenID and Forms authentication. However, initially, it was pretty much impossible to find good examples of how to accomplish this.
I did end up finding some useful demos and articles:
- OWIN Sample Application – straight-forward sample that I could create a prototype with to make sure everything worked.
- Rick Strahl’s blog – great write-up on his experience going through a similar conversion.
- Ben Foster’s blog – another great write-up that walks through implementing OWIN step-by-step.
Creating a Microsoft Identity Account
Next, I needed to create an application account for Microsoft Identity. When people sign in with their Microsoft account to DailyStory this is the “application” they are granting access to.
I’m not going to go into the details of what all the settings are, as there are plenty of better and more in-depth articles about that.
Suffice to say that you’ll need your Application Id (a GUID) and will need to add callback URLs. I added both production callback URLs and developer (e.g. localhost) callback URLs.
Creating a working prototype
I’m a big fan of creating small prototypes. It’s so much easier working with a simple sample than trying to navigate the nuances of a larger application.
I started with the OWN sample application and wired it up to use DailyStory’s Microsoft application identity. Believe it or not, that was actually relatively easy to get working (yes, I was surprised).
Next, I started integrating that into the DailyStory code base.
Changes to support OWIN
Below are the changes made:
1. Add access control
The first thing I did in the DailyStory code was to ensure that authentication/authorization was setup correctly. Rather than adding the [Authorize]
attribute to all the controllers, I added a global filter:
[csharp]
public static void RegisterGlobalFilters (GlobalFilterCollection filters)
{
filters.Add (new HandleErrorAttribute ());
filters.Add (new AuthorizeAttribute());
}
[/csharp]
Next, I added the [AllowAnonymous]
attribute onto any classes or controller methods, such as login, logout, etc.
2. OWIN Settings in web.config
After configuring what needed to be authenticated/authorized I added the appSettings that the OWIN middleware would look for:
[xml]
<add key=”ida:ClientId” value=”– YOUR APPLICATION ID HERE –“/>
<add key=”ida:AADInstance” value=”https://login.microsoftonline.com/{0}{1}”/>
<add key=”ida:RedirectUri” value=”https://app.dailystory.com/oauth/microsoft”/>
[/xml]
3. OwinStartup attribute
OWIN does some magic under the covers and one of the requirements is you have to tell OWIN which class contains the Configuration method. This is used by OWIN to look at all the requests. The sample application referenced above has a great example of this.
I did modify app.UseCookieAuthentication
‘s options to set both the cookie domain and the cookie name:
[csharp]
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
#if !DEBUG
CookieDomain = “.dailystory.com”,
#endif
CookieName = “.DSAUTH”
});
[/csharp]
The compilation check excludes the domain because it wouldn’t work when running as localhost.
In my case I added a second CookieAuthentication section to support custom cookies as well. I used the same CookieName and the OWIN middleware apparently encrypts the authentication source with the cookie.
4. OWN sign in
The OWIN sign in is, again, nearly identical to what I found in the sample:
[csharp]
[AllowAnonymous]
public void SignIn(string provider)
{
// provider is held for future use
// Send an OpenID Connect sign-in request.
if (!Request.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = “/msidentity” }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
}
[/csharp]
5. Authentication callback
At this point any requests to /signin/microsoft will redirect to Microsoft’s sign in page. After successfully authenticating it redirect back to the /msidentity path.
Within the controller’s method for msidentity we do the checks to determine if the authenticated user is known, i.e. is there a DailyStory tenant or tenants for that account. If it’s a valid user we redirect them to their tenant.
If the authenticated user is not known, we auto-provision a new trial account based on claims information found in the ClaimsPrincipal and then redirect them to their new trial.
Summary
Adding support for OWIN isn’t terribly difficult. I’ve left out a few details, but if you have questions don’t hesitate to ask!