Monday, April 29, 2013

Claims-based authentication in a web application using ACS

I like the idea to use existing user accounts for authentication instead of managing users by myself.
Otherwise I have to store user names and passwords in my database. Therefore I have to provide a user interface to create, change or delete them. And most important, I have to ensure that everything is secure. Nothing I really want to bother when I am developing some cool application.
Also for the user does not like to create a new account for every web site she visits. This is quite boring, especially as she should use different passwords for each site. That arises the need to store somewhere the different passwords?
To cut a long story short: why not use existing user accounts like Google, Windows Live ID, Facebook, … ?

Integrating ACS

A good starter is How to: Create My First Claims-Aware ASP.NET Application Using ACS. Unfortunately, this article is a little bit outdated in between (written in April 2011). Mainly the toolset (Visual Studio 2012, Identity and Access Tool) changed.

Web Application

To demonstrate the principle, start with an ASP.NET Empty Web Application. Add a Web Form with some text in the body like
Hello <%= User.Identity.Name %>
When you start the debugger, you should see a web page with text Hello – but without user name, since no authentication is done.

Configure ACS

Before we can add authentication, we have to do some configuration. Just follow the first steps from the document mentioned above (How to: Create My First Claims-Aware ASP.NET Application Using ACS):
  • Step 1 - Create an Access Control Namespace
  • Step 2 – Launch the ACS Management Portal
  • Step 3 – Add Identity Providers

Identity and Access Tool

With Visual Studio 2012 the ACS integration is no longer done with a STS Reference. Instead, the Identity and Access Tool has to be used. You can download it from Visual Studio Gallery. After installing it, you can start it in the Solution Explorer in the project’s context menu.
Since we want to connect to ACS, select the third option Use the Windows Azure Access Control Service:
Now we have to configure the providers. Just click on the Configure link in the middle:
The ACS namespace is easy to know. It’s just the name you chose. The management key is not so easy to find:
  • Open Windows Azure Portal
  • Manage your ACS namespace
  • Select Management service
  • Click ManagementClient
  • Click Symmetric Key
Here you can copy the key:
The next step is to select the providers you want to use in your application. And to specify realm and return url of your application. By default the are initialized with the url used for debugging in Visual Studio.
After clicking OK, you get a lot of stuff generated in your Web.config. Additionally, you can find in the Azure Portal an additional Relying Party Application (originally, this was step 4 from How to: Create My First Claims-Aware ASP.NET Application Using ACS.
When you start now the debugger, the first page is something like
The user can select with which identity provider she wants to use. After the login, the start page of your application should be displayed, showing the user name.

Fiddler

When you check the logon process in Fiddler, you will see the following requests:
  • http://localhost:58235/
    The URL of the application itself, redirects to
  • https://markus.accesscontrol.windows.net/v2/wsfederation?...
    The page to select the identity provider; selecting one forwards to
  • https://accounts.google.com/o/openid2/auth?...
    The login itself, here at Google; after confirmation redirects back to
  • https://markus.accesscontrol.windows.net/v2/openid?...
    ACS redirects back to the application itself
  • http://localhost:58235/

Claims

Since .NET 4.5 every Principal is based on a ClaimsPrincipal. That means every attribute of the user is a claim. It’s easy to query or display them:
System.Security.Claims.ClaimsPrincipal cp = (System.Security.Claims.ClaimsPrincipal)User;
foreach (var claim in cp.Claims)
{
}
With a Goggle account par example, you have at least for claims:

Specific claims

You can rely only on the existence of the claims http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider and http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier. All other claims are optional, also such convenient things like http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name or http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress. Par example Windows Live ID does not provide this information due to security restrictions.
This is especially boring, since the name claim will be mapped to User.Identity.Name. When the claim is missing, the Name property is null. So maybe you get runtime errors because of that. Therefore it could be a good idea to provide a default value for this claim.
You can do it in the Windows Azure Portal in the section Rule groups. Select the rule group of your application, and then you should see Passthrough rules, which forward the claims from the identity provider to your application. Here you add your own rules, e.g.:
  • Identity Provider: Windows Live ID
  • Input claim type: Any
  • Input claim value: Any
  • Output claim type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
  • Output claim value: ???
  • Description: Default name for Windows LiveID
With this rule in place, every user authenticated with Windows Live ID has the name ???.

Roles

Also roles are now claims. That means you can also define a rule to apply a role:
  • Identity Provider: Windows Live ID
  • Input claim type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
  • Input claim value: (the name identifier)
  • Output claim type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
  • Output claim value: admin
  • Description: Admin role for xxx
Now you can check the existence of the role, e.g. (or 1 one of the other 1,000,000 possibilities):
User.IsInRole("admin")

ClaimsAuthenticationManager

Adding roles or names via rules is not very feasible when you have more than 2 or 3 users. Therefore it is better to implement a ClaimsAuthenticationManager to extend the claims processing pipeline. Here you can modify the claims as you want:
public class MyClaimsAuthenticationManager : ClaimsAuthenticationManager
{
  public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
  {
    if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
    {
      ClaimsIdentity claimsIdentity = (ClaimsIdentity)incomingPrincipal.Identity;
      string identityProvider =
        claimsIdentity.Claims
          .Where(c => c.Type == "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider")
          .Select(c => c.Value)
          .FirstOrDefault();
      string nameIdentifier = 
        claimsIdentity.Claims
          .Where(c => c.Type ==ClaimTypes.NameIdentifier)
          .Select(c => c.Value)
          .FirstOrDefault();

      if (identityProvider == "uri:WindowsLiveID" && nameIdentifier == "FVUzvNwYGuC5cG4VYdWArf81SRj0QISjQpUIhaHonNE=")
      {
        claimsIdentity.AddClaim(new Claim(ClaimTypes.Name, "Markus Wagner"));
        claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
      }
    }

    return incomingPrincipal;
  }
}
Finally you have to configure your application to use the new ClaimsAuthenticationManager. This can be done in the Web.config:
<system.identityModel>
  <identityConfiguration>
    <claimsAuthenticationManager type="AcsAuthentication.MyClaimsAuthenticationManager, AcsAuthentication" />
  </identityConfiguration>
</system.identityModel>
For sure, in a real world application, you will not hard-code the claims here. Instead you will take them from a configuration file or a database. But the principle will stay the same.

Conclusion

For authentication, ACS is already a good alternative. Especially since you do not have to manage passwords.
With authentication it gets more complicated. Some prerequisites exist, but it isn't really comfortable.

Sunday, April 28, 2013

Writing your own Glimpse Plugin

As I wrote in my last post, Glimpse is a great tool to diagnose your web application. And there is already a lot of plugins available. But maybe you have the need to get some additional info, for which no plugin is available so far. In such a case it is quite easy to write your own plugin.
I will show it with a plugin for Log4Net. Before you ask, yes there is already a Glimpse.Log4Net plugin. Unfortunately this package is outdated. It was written for Glimpse 0.86, but with 1.x it doesn't work anymore.
UPDATE 15-Jun-2013: In between the Glimpse.Log4Net plugin has been updated to support Glimpse 1.x. But nevertheless the how to below should be interesting enough, since there is not a lot of documentation out there.

Log4Net and Trace

It is not absolute necessary to use a special Log4Net plugin. Instead it is possible to redirect the Log4Net output to the Tracing infrastructure. And for this, Glimpse provides already a tab.
All you need is a new appender:
<appender name="TraceAppender" type="log4net.Appender.TraceAppender">
  <category value="%level" /> 
  <layout type="log4net.Layout.PatternLayout"> 
    <conversionPattern value="%logger - %message" /> 
  </layout> 
</appender>
After connecting it to a logger, you will see all relevant log lines in the trace tab. With the specification of the category tag, the trace output will have the same level as the original Log4Net log line. Therefore some of the outputs are prefixed with the corresponding icons:
 

Log4Net Plugin

The implementation of the plugin is straightforward: first we need a Log4Net appender, which collects the messages to display in Glimpse. And we need an implementation for the tab in the Glimpse window. The rest in some infrastructure around it.
So let's have a look at the details.

Log4NetMessage

This is a simple container for the data transferred from the Log4Net appender to Glimpse. The only prerequisite is, it has to implement the interface Glimpse.Core.Message.IMessage:

public class Log4NetMessage : IMessage
{
  public Log4NetMessage()
  {
    Id = Guid.NewGuid();
  }

  public Guid Id { get; private set; }
  public TimeSpan FromFirst { get; set; }
  public TimeSpan FromLast { get; set; }
  public string ThreadName { get; set; }
  public string Level { get; set; }
  public string LoggerName { get; set; }
  public string Message { get; set; }
}

Log4NetInspector

Next we need some additional infrastructure. The appender sends the message to the tab via a Glimpse.Core.Extensibility.IMessageBroker. This must be set from outside.
Therefore I added an implementation of Glimpse.Core.Extensibility.IInspector, whose Setup method will be called at startup. It takes the needed properties from the Glimpse context and stores them in static properties of my appender:
public class Log4NetInspector : IInspector
{
  public void Setup(IInspectorContext context)
  {
    GlimpseAppender.Initialize(context.MessageBroker, context.TimerStrategy);
  }
}

GlimpseAppender

Now it's time for the real stuff, first the appender. The implementation is quite easy, a bigger part of the code is about the calculation of the elapsed time since the last call (this part could be also skipped).
public class GlimpseAppender : AppenderSkeleton
{
  private static IMessageBroker _messageBroker;
  private static Func<IExecutionTimer> _timerStrategy;

  private static Stopwatch fromLastWatch;

  public static void Initialize(IMessageBroker messageBroker, Func<IExecutionTimer> timerStrategy)
  {
    _messageBroker = messageBroker;
    _timerStrategy = timerStrategy;
  }

  protected override void Append(LoggingEvent loggingEvent)
  {
    if (_timerStrategy != null && _messageBroker != null)
    {
      IExecutionTimer timer = _timerStrategy();
      if (timer != null)
      {
        _messageBroker.Publish(new Log4NetMessage
          {
            ThreadName = loggingEvent.ThreadName,
            Level = loggingEvent.Level.DisplayName,
            LoggerName = loggingEvent.LoggerName,
            Message = loggingEvent.RenderedMessage,
            FromFirst = timer.Point().Offset,
            FromLast = CalculateFromLast(timer)
          });
      }
    }
  }

  private static TimeSpan CalculateFromLast(IExecutionTimer timer)
  {
    if (fromLastWatch == null)
    {
      fromLastWatch = Stopwatch.StartNew();
      return TimeSpan.FromMilliseconds(0);
    }

    // Timer started before this request, reset it
    if (DateTime.Now - fromLastWatch.Elapsed < timer.RequestStart)
    {
      fromLastWatch = Stopwatch.StartNew();
      return TimeSpan.FromMilliseconds(0);
    }

    var result = fromLastWatch.Elapsed;
    fromLastWatch = Stopwatch.StartNew();
    return result;
  }
}

Log4NetTab

Now we are ready for the tab's implementation. It inherits from Glimpse.Core.Extensibility.TabBase, and implements the interfaces Glimpse.Core.Extensibility.ITabSetup, Glimpse.Core.Extensibility.IKey and Glimpse.Core.Extensibility.ITabLayout. As you see, the biggest part is the definition of the layout, how the data will be displayed on the tab.
public class Log4NetTab : TabBase, ITabSetup, IKey, ITabLayout
{
  private static readonly object layout = TabLayout.Create()
    .Row(r =>
    {
      r.Cell(0).WidthInPixels(80);
      r.Cell(1).WidthInPixels(80);
      r.Cell(2);
      r.Cell(3);
      r.Cell(4).WidthInPercent(15).Suffix(" ms").AlignRight().Prefix("T+ ").Class("mono");
      r.Cell(5).WidthInPercent(15).Suffix(" ms").AlignRight().Class("mono");
    }).Build();

  public override object GetData(ITabContext context)
  {
    return context.GetMessages<Log4NetMessage>().ToList();
  }

  public override string Name
  {
    get { return "Log4Net"; }
  }

  public void Setup(ITabSetupContext context)
  {
    context.PersistMessages<Log4NetMessage>();
  }

  public string Key
  {
    get { return "glimpse_log4net"; }
  }

  public object GetLayout()
  {
    return layout;
  }
}

Log4NetMessagesConverter

The final part is a converter, which knows how to display a Log4NetMessage in the layout of Log4NetTab:
public class Log4NetMessagesConverter : SerializationConverter<IEnumerable<Log4NetMessage>>
{
  public override object Convert(IEnumerable<Log4NetMessage> obj)
  {
    var root = new TabSection("Level", "ThreadName", "LoggerName", "Message", "From Request Start", "From Last");
    foreach (var item in obj)
    {
      root.AddRow().
        Column(item.Level).
        Column(item.ThreadName).
        Column(item.LoggerName).
        Column(item.Message).
        Column(item.FromFirst).
        Column(item.FromLast).
        Style(GetStyle(item.Level));
    }
      return root.Build();
  }

  private static string GetStyle(string levelDisplayName)
  {
    switch (levelDisplayName)
    {
      case "EMERGENCY":
      case "FATAL":
      case "ALERT":
        return FormattingKeywords.Fail;

      case "CRITICAL":
      case "SEVERE":
      case "ERROR":
        return FormattingKeywords.Error;

      case "WARN":
        return FormattingKeywords.Warn;

      case "NOTICE":
      case "INFO":
        return FormattingKeywords.Info;

      case "DEBUG":
      case "FINE":
      case "TRACE":
      case "FINER":
      case "VERBOSE":
      case "FINEST":
      case "ALL":
        return FormattingKeywords.Quiet;

      default:
        return FormattingKeywords.Quiet;
    }
  }
}

Result

Finally you have to add the GlimpseAppender to your Log4Net configuration. When you start now your application, you should have a new Log4Net tab in the Glimpse window. Its content is similar to the Trace tab above, but the data is better structured.
NOTE: Be sure to start the application really from scratch. E.g. stop an already running IISExpress before. Otherwise it could be the Glimpse setup is not working as expected.

You can find the source code at GitHub: https://github.com/Ritzlgrmft/GlimpseDemo.

Saturday, April 27, 2013

Web diagnostics with Glimpse

Glimpse is a great tool to get more info what is going on your web server. And it is easy to use: for my demo, I created a new ASP.NET MVC 4 Web Application (it works also with other MVC versions, and also with ASP.NET Web Forms) with the Internet Application template (again, it works also with the other templates). Then I added the NuGet package Glimpse.Mvc4. Finally I pressed F5, the application started and - nothing changed! No hint of Glimpse.
The reason is that Glimpse has to be enabled first. For this I opened the page Glimpse.axd in the root of my web application:
I clicked on Turn Glimpse On, went back to my application home page, refreshed it, and now in the bottom right corner was the Glimpse icon: . Clicking on this icon, I got the Glimpse window, displaying several tabs with some info used to produce the current web page:

NOTE: Glimpse stores the info if it is enabled or not in a cookie called glimpsePolicy. That means, when you later access the page again, Glimpse will be enabled already (or not).

When you look at the Glimpse tabs, some like Request, Server or Trace appear familiar from ASP.NET Tracing. But there are also some other tabs. Just play around with them a little bit.

Entity Framework Plugin

As useful as Glimpse is so far - that is not all. You can easily add additional tabs to Glimpse. A complete list of all available packages can be found on the Glimpse Extensions page.
The Internet Application template I used above contains some database access in combination with the user stuff (Log in, Register). Therefore I added now the Entity Framework Plugin.
I just had to download the NuGet package Glimpse.EF5. After compiling I refreshed the home page and found a new SQL tab in the Glimpse window. Only the tab was disabled since no database access was done for the home page.
Then I logged in, but again the SQL tab was disabled. This happened because there several requests executed for the log in, and only the last request didn't access the database. For problems like this Glimpse provides the History tab:
Here I selected the correct request, clicked Inspect, and finally the SQL tab was enabled:
Great, isn't it? A lot of useful info, and no effort to get them.