Scott Hanselman

Adding Two-Factor authentication to an ASP.NET application

April 8, '14 Comments [16] Posted in ASP.NET | ASP.NET MVC
Sponsored By
German Lorenz cipher machine by Timitrius used under CC Attributin

ASP.NET Identity 2.0 was released last month and it's got a number of significant updates and new features that are worth checking out. For historical context, read the "Introduction to ASP.NET Identity" article that includes a lot of background and information on why certain decisions were made, as well as an  overview of some of the goals of ASP.NET Identity 2.0 like:

  • One Identity system for ASP.NET Web Forms, MVC, Web API, and Web Pages
  • Total control over user profile schema.
  • Pluggable storage mechanisms from Windows Azure Storage Table Service to NoSQL databases
  • Unit Testable
  • Claims-based Auth adds more choice over simple role membership
  • Social Logins (MSFT, FB, Google, Twitter, etc)
  • Based on OWIN middleware, ASP.NET Identity has no System.Web dependency

You can watch a video of Pranav Rastogi and I upgrading the ASP.NET Membership systems on an older ASP.NET application to the latest bits. There's also migration docs in detail:

ASP.NET Identity is on CodePlex today (and soon to be open sourced...paperwork) at https://aspnetidentity.codeplex.com/ or access the NuGet feed for nightly builds.

Adding Two-Factor authentication to an ASP.NET application

I recently changed all my accounts online to two-factor auth, and I really recommend you do as well. Here's how to add Two-Factor Auth to an ASP.NET application using Identity 2.0.

You'll have a class that is a UserManager that handles access to users and how they are stored. Inside this manager there's an IIdentityMessageService that you can implement to validate a user with whatever you want, like email, SMS, or a time-based token.

Send Verification Code

Here's an example SmsService where I'm using Twilio to send text messages. Again, you can do whatever you want in your implementation.

public class SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
// Plug in your sms service here to send a text message.
message.Destination = Keys.ToPhone; //your number here
var twilio = new TwilioRestClient(Keys.TwilioSid, Keys.TwilioToken);
var result = twilio.SendMessage(Keys.FromPhone, message.Destination, message.Body);

return Task.FromResult(0);
}
}

If I were sending an EmailMessage, I'd do something like this. Note it's just another implementation of the same simple interface:

public class EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
{
string text = message.Body;
string html = message.Body;
//do whatever you want to the message
MailMessage msg = new MailMessage();
msg.From = new MailAddress("scott@hanselman.com");
msg.To.Add(new MailAddress(message.Destination));
msg.Subject = message.Subject;
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));

SmtpClient smtpClient = new SmtpClient("smtp.whatever.net", Convert.ToInt32(587));
System.Net.NetworkCredential credentials = new System.Net.NetworkCredential(Keys.EmailUser, Keys.EMailKey);
smtpClient.Credentials = credentials;
smtpClient.Send(msg);

return Task.FromResult(0);
}
}

In your IdentityConfig.cs you can register as many TwoFactorProviders as you'd like. I'm adding both Email and Sms here. They include token providers but again, everything is pluggable.

manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser> {
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser> {
Subject = "SecurityCode",
BodyFormat = "Your security code is {0}"
});

manager.EmailService = new EmailService();
manager.SmsService = new SmsService();

If a user tries to login you need to make sure they are a VerifiedUser. If not, get a valid two factor provider and send them a code to validate. In this case, since there are two providers to choice from, I let them pick from a dropdown. Here's the POST to /Account/SendCode:

public async Task<ActionResult> SendCode(SendCodeViewModel model)
{
// Generate the token and send it
if (!ModelState.IsValid)
{
return View();
}

if (!await SignInHelper.SendTwoFactorCode(model.SelectedProvider))
{
return View("Error");
}
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl });
}

The sender of the two factor code depends on your implementation, of course.

public async Task<bool> SendTwoFactorCode(string provider)
{
var userId = await GetVerifiedUserIdAsync();
if (userId == null)
{
return false;
}

var token = await UserManager.GenerateTwoFactorTokenAsync(userId, provider);
// See IdentityConfig.cs to plug in Email/SMS services to actually send the code
await UserManager.NotifyTwoFactorTokenAsync(userId, provider, token);
return true;
}

When it's time to get the code from them, they need to have logged in with name and password already, and we're now checking the code:

[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string provider, string returnUrl)
{
// Require that the user has already logged in via username/password or external login
if (!await SignInHelper.HasBeenVerified())
{
return View("Error");
}
var user = await UserManager.FindByIdAsync(await SignInHelper.GetVerifiedUserIdAsync());
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl });
}

We can sign users potentially a number of ways, like with External Sign Ins (Twitter, etc) but here's the TwoFactorSignIn

public async Task<SignInStatus> TwoFactorSignIn(string provider, string code, bool isPersistent, bool rememberBrowser)
{
var userId = await GetVerifiedUserIdAsync();
if (userId == null)
{
return SignInStatus.Failure;
}
var user = await UserManager.FindByIdAsync(userId);
if (user == null)
{
return SignInStatus.Failure;
}
if (await UserManager.IsLockedOutAsync(user.Id))
{
return SignInStatus.LockedOut;
}
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, provider, code))
{
// When token is verified correctly, clear the access failed count used for lockout
await UserManager.ResetAccessFailedCountAsync(user.Id);
await SignInAsync(user, isPersistent, rememberBrowser);
return SignInStatus.Success;
}
// If the token is incorrect, record the failure which also may cause the user to be locked out
await UserManager.AccessFailedAsync(user.Id);
return SignInStatus.Failure;
}

If you want this blog post's sample code, make an EMPTY ASP.NET Web Application and run this NuGet command from the Package Manager Console

Install-Package Microsoft.AspNet.Identity.Samples -Pre

Have fun!

Related Links

* Photo of German Lorenz cipher machine by Timitrius used under CC Attribution 


Sponsor: Big thanks to Novalys for sponsoring the blog feed this week! Check out their security solution that combines authentication and user permissions. Secure access to features and data in most applications & architectures (.NET, Java, C++, SaaS, Web SSO, Cloud...). Try Visual Guard for FREE.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

If you're not using Glimpse with ASP.NET for debugging and profiling, you're missing out

July 20, '13 Comments [40] Posted in ASP.NET | ASP.NET MVC | Open Source | Tools
Sponsored By
Glimpse NuGet packages

I've blogged about Glimpse since the day I first saw it at Mix 2011's open source fest. It's popular, but frankly, Glimpse is so useful more people need to know about it.

From within your ASP.NET application in Visual Studio, install Glimpse using NuGet. You'll want to install the right Glimpse packages for the ASP.NET features you're using. For example, I'm using MVC4 and Entity Framework 5, so I will use NuGet and:

install-package Glimpse.MVC4
install-package Glimpse.EF5

These packages pull in the core Glimpse libraries plus the hooks for the specific ASP.NET modules and handlers needed for Glimpse to collect all the information about your application and present it to the client side. Be sure to pick the right NuGet packages for your project type.

The releases of Glimpse 1.4.0, and now most recently 1.5.0 improve Glimpse with the addition of a really amazing HUD (Heads Up Display). As you hover over each segment, it pops up with lots of details about the HTTP request, AJAX requests, deep inspection database interactions, and lots more.

Glimpse's new HUD

Here I've hovered over one segment and you can see the time it took to render this first page, and exactly how much time was spent during each activity, from rendering to action methods to database connections.

The Glimpse HUD expanded

You can move from the HUD to the standard Glimpse view. The best part is that each Glimpse Tab is a plugin itself! There's a whole community creating Glimpse Plugins. If you're using RavenDB, or NHibernate, or SignalR or whatever, you can get introspection into what's going on in a Glimpse Tab.

You turn Glimpse on and off with cookies, and you can setup security policy however you want. Glimpse isn't in the background creeping around - you have absolute control over when you want it used. Perhaps local and only when debugging, or perhaps always and with a specific cookie value, it's up to you.

Below you can see the actual SQL query executed by my Entity Framework code and how long it took to execute. I didn't have to change any part of my code or do anything more than just install Glimpse. Glimpse added the modules and handlers, and Glimpse policies can be installed to turn Glimpse on or off based on any option I can think of. I can even put Glimpse into production and only turn it on for certain requests, giving me a profiling tool I can peek at whenever I like.

EF SQL queries viewed within Glimpse

You likely use F12 developer tools in Chrome, IE and Firefox, and you've seen Timeline views before. But remember that Glimpse is JavaScript and HTML on the client - it's NOT a browser plugin - and it's a series of plugins on the server that give you a holistic view that's way more than just what's visible on the client.

Glimpse's Timeline View shows you exactly what's happening on the server, how long it's taking, and how it all fits together.

image

Sessions within Glimpse are all tracked and be optionally named. Since the server is collecting what's going on, you can pull out a popup browser window of Glimpse and connect to sessions from other browsers. Below I'm using an iPhone mobile emulator from ElectricPlum and inspecting requests from another browser window.

Using Glimpse to debug remotely against an iPhone Emulator

Glimpse is all open source and under the Apache 2.0 license. You can certainly help out, but the most interesting thing in my opinion is writing Glimpse Tabs - extending Glimpse to collect and show new data. Tabs can show technical stuff, but even business stuff that's specific to your application or style of application. For example, the Umbraco CMS could make a Glimpse Tab that puts configuration or technical Umbraco specific details up front. A line of business app could show tax details or shopping cart contents.

Glimpse is so useful that it's the first thing I install after I File | New Project on any non-trivial thing I'm working on. It's replaced Mini-Profiler as my go-to "production profiler" for web apps, and if you use ELMAH to collect and manage your application errors, there's even a Glimpse ELMAH plugin!

Check it out and go talk to Anthony and Nik about Glimpse on Twitter and thank for their work!

DISCLOSURE NOTE: The Red Gate company sponsors the Glimpse open source project. Red Gate also sponsored my blog feed this week. That is a cool coincidence, but it's just a coincidence. Red Gate does a lot of stuff. This post about Glimpse was written earlier. Just an FYI for y'all.


Sponsor: Big thanks to the folks at Red Gate for sponsoring the feed this week. Take a moment and check out their free download of Deployment Manager! Easy release management: Deploy your .NET apps, services and SQL Server databases in a single, repeatable process with Red Gate’s Deployment Manager. There’s a free Starter edition, so get started now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Building Web Apps with ASP.NET Jump Start - 8 Hours of FREE Training Videos

February 28, '13 Comments [41] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | Screencasts | SignalR | Speaking
Sponsored By
image

Last week Jon Galloway, Damian Edwards and myself (with a raspy throat) were up in Redmond at the Microsoft Campus filming at Microsoft Virtual Academy.

They've got a whole studio there so we spent the whole day presenting LIVE. There were several thousand folks watching live and interacting with

Very special thanks to Brady Gaster and ASP.NET community members Scott Koon, Peter Mourfield, and Rob Chartier who were furiously handling questions in the chats! Your volunteerism and dedication to the community is deeply appreciated! Let's give them a hand, eh?

Jon worked very hard to put together a great day of content based on the successful Web Camps classes we've given all over the world. We took all this and worked to update it with all the new improvements in the ASP.NET and Web Tools 2012.2 release last week so it's very up to date.

Building Web Apps with ASP.NET Jump Start: (01) What's New in ASP.NET 4.5

Building Web Apps with ASP.NET Jump Start: (01) What's New in ASP.NET 4.5

This module will review what's new in ASP.NET 4.5. It will provide an overview of strongly typed data controls and model binding in web forms, friendly URLs, page inspector, Visual Studio Web Editor features and much more.

 

Building Web Apps with ASP.NET Jump Start: (02) Building and Deploying Websites with ASP.NET MVC 4Building Web Apps with ASP.NET Jump Start: (02) Building and Deploying Websites with ASP.NET MVC 4

In this session the instructors go over ASP.NET MVC 4 and provide several demos on creating a new site; adding a model, controller and view, to using entity framework code first. Lastly they demo how to deploy to Windows Azure Web Sites.

 

Building Web Apps with ASP.NET Jump Start: (03) Creating HTML5 Applications with jQueryBuilding Web Apps with ASP.NET Jump Start: (03) Creating HTML5 Applications with jQuery

This module introduces you to the new standards of HTML5 and provides a demo of how powerful it is. Additionally you will see how it works with ASP.NET MVC 4, jQuery overview, Visual Studio Web Tools, Web Essentials and SPLA Template.

 

Building Web Apps with ASP.NET Jump Start: (04) Building a Service Layer with ASP.NET Web APIBuilding Web Apps with ASP.NET Jump Start: (04) Building a Service Layer with ASP.NET Web API

Have you always want to know how to build a service layer with ASP.NET Web API? This segment shows how ASP.NET Web API fits in, and how to consume Web API from jQuery and Windows 8.

 

Building Web Apps with ASP.NET Jump Start: (05) Leveraging Your ASP.NET Development Skills to Build Office Apps Building Web Apps with ASP.NET Jump Start: (05) Leveraging Your ASP.NET Development Skills to Build Office Apps

Get ready to see several Demos leveraging ASP.NET skills to build apps for Office specifically using HTML 5+ jQuery and ASP.NET Web API. This module will also go into further details regarding apps for Office and how they work. Using jQuery inside Office is freaky and cool.

 

Building Web Apps with ASP.NET Jump Start: (06) Building and Leveraging Social Services in ASP.NET Building Web Apps with ASP.NET Jump Start: (06) Building and Leveraging Social Services in ASP.NET

In this session you will see how to using social authentication with ASP.NET as well as an overview of the new Facebook application template.

 

Building Web Apps with ASP.NET Jump Start: (07) Building for the Mobile Web Building Web Apps with ASP.NET Jump Start: (07) Building for the Mobile Web

This module will provide and overview of adaptive rendering in ASP.NET 4.5 and ASP.NET MVC 4. This is especially important since mobile is fast becoming the primary way people browse the web. We'll also cover jQuery Mobile.

 

Building Web Apps with ASP.NET Jump Start: (08) Real-time Communication with SignalR Building Web Apps with ASP.NET Jump Start: (08) Real-time Communication with SignalR

In this segment the instructors go over SignalR, and an incredibly simple real-time web for .NET. It will also provide an overview for real-time hit counter, what SignalR is and how to build a chat application, a multi-player game and load balancing SignalR.

 

Building Web Apps with ASP.NET Jump Start: (09) Taking Advantage of Windows Azure Services Building Web Apps with ASP.NET Jump Start: (09) Taking Advantage of Windows Azure Services

And where would we be if we could not scale it all up or down. This flexibility can be provided with Windows Azure. Here you will see how Windows Azure fits in with mobile services, virtual machines while managing caching and storage.

 

I hope you enjoy the day! Here's a complete course outline with jumps to specific spots:

Building Web Apps with ASP.NET Jump Start

If you’d like more information, including links to a lot of the sample code, see Jon’s wrap-up post.

Related Links

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Released: ASP.NET and Web Tools 2012.2 in Context

February 18, '13 Comments [87] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | VS2012
Sponsored By

One ASP.NETLast year the ASP.NET team started talking about something we're calling "One ASP.NET." I showed some mockups of our ideas last summer at the aspConf Keynote that you can watch online.

We also announced then that we would add new features to ASP.NET as out of band releases (OOB) without breaking existing functionality. This means that developers don't have to wait for the next version of Visual Studio for great web development features today. We're aiming to add to ASP.NET and Web Tools every 6 months.

For those that don't want to wait, Mads and the team also started a feature playground called Web Essentials. This is an extension to Visual Studio that updates all the time with ideas and brainstorms about how VS can be an even better editor for the web. As features "graduate" from Web Essentials, they move into ASP.NET and Web Tools proper. A bunch of features graduate with today's release.

Today we announced ASP.NET and Web Tools 2012.2. You can use the Web Platform Installer to get ASP.NET and Web Tools 2012.2 now.

Get it with the Online Installer:

Get ASP.NET and Web Tools 2012.2 with Web Platform Installer

OR use the Offline Installers:

1. Get the ASP.NET 2012.2 pieces then get one of these

2. Web Tools 2012.2 for any regular Visual Studio 2012 or  Web Tools 2012.2 for Visual Studio Web Express 

Here's some highlights:

Editors

Syntax Highlighting for client side templating languages within the HTML editor like:

  • CoffeeScript
  • Mustache
  • Handlebars
  • JsRender

Other editors get new features as well:

  • Syntax Highlighting, intellisense and validation for LESS files.
  • Intellisense for Knockout.js bindings!
  • CSS Auto Sync - type into the CSS editor while the site running and get live updates in Page Inspector
  • Everyone's favorite "Paste JSON as Class." Copy some JSON into the clipboard, paste and get either C# or VB classes for your JSON to serialize into.

Browsers

Mobile Emulator support adds extensibility hooks so that third-party emulators and unusual browsers can be installed as a VSIX. The installed emulators will show up in the F5 dropdown, so that developers can preview their websites on a variety of devices. Read more about this feature in my entry on the new BrowserStack integration with Visual Studio.

Packages

With today’s release, all of the ASP.NET templates have updated versions of jQuery, jQuery UI, jQuery Validation, Modernizr, Knockout, and other open source NuGet packages. Your existing projects won't update unless you update them explicitly.

ASP.NET

  • OData support in ASP.NET Web API
  • SignalR included out of the box and fully supported
  • Web Forms now supports Friendly URLs (no more .aspx extension)
  • Web Forms supports device (mobile) specific pages, so product.aspx can also have product.mobile.aspx.
  • Updated Single Page Application template
  • MVC Facebook Application Template
  • Web Sites get the same publishing tools as Web Projects

These are just the highlights. But let me call out one specific feature that gets us closer to one of the main goals for One ASP.NET which is what I call a more level playing field.

Community Project Templates

One of the most significant "under the hood" changes is the ability to add a project template via a VSIX.

We'll be seeing an update to the Visual Studio Gallery soon that will make it so you can upload your own VSIX files (Visual Studio Extensions) that can be installed (and easily updated) into the ASP.NET MVC File New Project dialog with one click.

It's important to know that we're only halfway there. This is likely not what the final unified One ASP.NET dialog will end up looking like, but it's a start as it's a good place to open up for new templates.

Phrased differently, project templates should be as easy to share as NuGet packages. That's a goal.

Another goal is to be able to take an example project that looks the way you want, with the NuGet packages setup as you like them, then "Save As | Project Template" then publish the resulting template/VSIX to the gallery. That means projects like NancyFX, or FubuMvc or whatever you can think of can live next to out of the box templates.

Here's the initial documentation on how you can create VSIXs of project templates, get in this dialog and make it easy to spread your vision of a great web app. We are working to make this process fewer steps and unify things, but this works great now with VS2012.2 so you can get started today. Stay tuned for more on this.

In the near future we'd like to see the community sharing project templates that look the way the community wants them to look, living side by side with templates from Microsoft.

The fully populated ASP.NET MVC 4 New Project dialog has many new templates

As start, we're announcing four Single Page Application (SPA) templates you can install now. Please note that these community templates could be anything, the VSIX hooks are wide open, it's just that the first few happen to be SPA templates.

And, a clever play on words from John Papa (because what do you get in a SPA?)

  • HotTowel - a more complex template that includes knockout, bootstrap, sammy, toastr, q, momentjs, breeze and puts them all together into one SPA example.

Note how nice the HTML editor looks when working on an Ember project, for example. We've got syntax highlighting, HTML5 Intellisense and coloring in our Mustache templates.

Mustache template syntax highlighting

Remember, you'll need the 2012.2 release to see these new templates, so use Web Platform Installer to get ASP.NET and Web Tools 2012.2 now. And, if you want check out our future playground features like Zen Coding, CoffeeScript and lots more, also pick up Web Essentials. Note that Web Essentials is a small extension and if it causes you any trouble you can just disable it.

Should you fear this release?

ASP.NET and Web Tools 2012.2 doesn't change any GAC'ed (Global Assembly Cache) files. It won't mess up your install of ASP.NET or change any existing projects. It's changes are either tooling within Visual Studio, or additions and improvements via local NuGet packages.

Go get it. ASP.NET and Web Tools 2012.2

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web

Integrating Mozilla Persona with ASP.NET

January 24, '13 Comments [13] Posted in ASP.NET | ASP.NET MVC | ASP.NET Web API | Open Source
Sponsored By

imageASP.NET and Web Tools 2012.2 is coming soon, but one of the features of ASP.NET that you can use TODAY is support for Google, Twitter, Microsoft and Facebook logins out of the box with ASP.NET templates. I show how OAuth in ASP.NET works in this 5 minute video. We are also continuing to look at ways to make membership easier in coming versions of ASP.NET like including things like this out of the box.

Mozilla has a new identity system called Mozilla Persona that uses browserid technology to let users log in to your site without creating a custom login or username.

I wanted to see how Persona would work in ASP.NET and hacked up a prototype (with some sanity checking from my buddy Hao Kung). There's some comments and some TODOs, but it's a decent proof of concept.

First, I read the Mozilla Persona Developer docs and got their fancy button CSS, then added it all to the ExternalLoginsListPartial view.

The Magic Persona button is very blue

The ProviderName check is there just because all the buttons look the same except the Persona one. A better way, perhaps, would be partial views for each button, or a custom helper.

@foreach (AuthenticationClientData p in Model)
{
if(p.AuthenticationClient.ProviderName == "Persona") //ya, ya, I know.
{
if (!Request.IsAuthenticated) {
<p><a href="#" class="persona-button" id="personasignin"><span>Sign in with your Email</span></a></p>
}
<!-- The CSS for this is in persona-buttons.css and is bundled in in BundleConfig.cs -->
}else{
<button type="submit" name="provider" value="@p.AuthenticationClient.ProviderName" title="Log in using your @p.DisplayName account">@p.DisplayName</button>
}
}

After the login dialog, an AJAX call to do the login locally posts data to my new PersonaController. except it doesn't POST its assert as JSON, but rather as a simple (standard) POST value. That is, just "assertion: longvalue."

function onAssertion(assertion) {
if (assertion) {
$.ajax({ /* <-- This example uses jQuery, but you can use whatever you'd like */
type: 'POST',
url: '/api/persona/login', // This is a URL on your website.
data: { assertion: assertion, },
success: function (res, status, xhr) { window.location.reload(); },
error: function (res, status, xhr) { alert("login failure" + res); }
});
}
else {
alert('Error while performing Browser ID authentication!');
}
}

ASP.NET Web API doesn't grab simple POSTs cleanly by default, preferring more formal payloads. No worries, Rick Strahl solved this problem with this clever SimplePostVariableParameterBinding attribute which allows me to just have string assertion in my method.

Armed with this useful attribute (thanks Rick!) my PersonaController login is then basically:

  • Get the assertion we were given from Persona on the client side
  • Load up a payload with that assertion so we can POST it back to Persona from the Server Side.
  • Cool? We're in, make a local UserProfile if we need to, otherwise use the existing one.
  • Set the FormsAuth cookie, we're good.

Here is the work:

[SimplePostVariableParameterBinding]
public class PersonaController : ApiController
{
// POST api/persona
[HttpPost][ActionName("login")]
public async Task<HttpResponseMessage> Login(string assertion) {
if (assertion == null) {
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
var cookies = Request.Headers.GetCookies();
string token = cookies[0]["__RequestVerificationToken"].Value;
//TODO What is the right thing to do with this?

using (var client = new HttpClient()) {
var content = new FormUrlEncodedContent(
new Dictionary<string, string> {
{ "assertion", assertion },
{ "audience", HttpContext.Current.Request.Url.Host }
//TODO: Can I get this without digging in HttpContext.Current?
}
);
var result = await client.PostAsync("https://verifier.login.persona.org/verify", content);
var stringresult = await result.Content.ReadAsStringAsync();
dynamic jsonresult = JsonConvert.DeserializeObject<dynamic>(stringresult);
if (jsonresult.status == "okay") {
string email = jsonresult.email;

string userName = null;
if (User.Identity.IsAuthenticated) {
userName = User.Identity.Name;
}
else {
userName = OAuthWebSecurity.GetUserName("Persona", email);
if (userName == null) {
userName = email; // TODO: prompt for custom user name?
using (UsersContext db = new UsersContext()) {
//TODO: Should likely be ToLowerInvariant
UserProfile user = db.UserProfiles.FirstOrDefault(u => u.UserName.ToLower() == userName.ToLower());
// Check if user already exists
if (user == null) {
// Insert name into the profile table
db.UserProfiles.Add(new UserProfile { UserName = userName });
db.SaveChanges();
}
}
}
}

OAuthWebSecurity.CreateOrUpdateAccount("Persona", email, userName);

FormsAuthentication.SetAuthCookie(email, false);
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}

[HttpPost][ActionName("logout")]
public void Logout() {
WebSecurity.Logout();
}
}

You click Sign in and get the Persona login dialog:

Animation of the Persona login

At this point, you're logged into the site with a real UserProfile, and things with ASP.NET Membership work as always. You can add more external logins (Twitter, Google, etc) or even add a local login after the fact.

You are logged in!

As I said, this isn't ready to go, but feel free to poke around, do pull requests, fork it, or comment on how my code sucks (in a kind and constructive way, because that's how we do things here.)

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Page 1 of 34 in the ASP.NET MVC category Next Page

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.