What's new? | Help | Directory | Sign in
Google
extremeswankopenid
ExtremeSwank OpenID Consumer for .NET
  
  
  
  
    
Search
for
Updated May 15, 2008 by j...@extremeswank.com
Labels: Featured
UsageExamples  
Examples for successfully using the OpenID Consumer

NOTE: These examples are for the 3.x API. For information on using the 4.x API, see the Programming documentation at http://extremeswank.com/OpenIDDoc/Index.html.

OpenID Authentication using Events (ASP.NET)

Use the OpenIDConsumer class to perform authentication requests, and respond to authentication responses from OpenID Providers.

using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Plugins.Extensions;
 
public partial class _Default {
 
    protected void Page_Load(object sender, EventArgs e)
    {
        // If this is not a postback, start up the Consumer
        // and handle any OpenID response messages, if present
        if (!IsPostBack)
        {

            OpenIDConsumer openid = GetConsumer();
 
            // Read the arguments in the current request and
            // automatically validate any OpenID responses,
            // firing events when actions occur.
            openid.HandleResponses();
        }
    }
 
    protected OpenIDConsumer GetConsumer()
    {
        // Initialize a new OpenIDConsumer, reading arguments
        // from the current request, and using Session and
        // Application objects to store data.  For more
        // flexibility, see "Disabling Stateful Mode" and 
        // "Persisting Stateful Data" below for more information.
        OpenIDConsumer openid = new OpenIDConsumer();
 
        // Subscribe to all the events that could occur
        openid.ValidationSucceeded += new EventHandler(openid_ValidationSucceeded);
        openid.ValidationFailed += new EventHandler(openid_ValidationFailed);
        openid.ReceivedCancelResponse += new EventHandler(openid_ReceivedCancelResponse);
          
        // Subscribing to SetupNeeded is only needed if using immediate authentication
        openid.SetupNeeded += new EventHandler(openid_SetupNeeded);
 
        return openid;
    }
 
    // This is the OnClick event for the submit button next to the OpenID text box.
    protected void Button_Click(object sender, EventArgs e)
    {
        // Create an OpenIDConsumer using default settings
        // (see Page_Load() above)
        OpenIDConsumer openid = GetConsumer();

        // Set the Identity to what the user entered on the form.
        openid.Identity = LoginBox1.Text;

        // Do an immediate request (go to the OpenID Provider to see if the user
        // is logged in - if not, will immediately come back and fire a SetupNeeded
        // event.  If you'd rather do a normal request, use BeginAuth() or
        // BeginAuth(false, true).)
        openid.BeginAuth(true, true);
    }
 
    // The following events were registered in the GetConsumer() method above.
 
    protected void openid_ReceivedCancelResponse(object sender, EventArgs e)
    {
        // Request has been cancelled. Respond appropriately.
    }
 
    protected void openid_ValidationSucceeded(object sender, EventArgs e)
    {
        // User has been validated!  Respond appropriately.
        OpenIDUser thisuser = ((OpenIDConsumer)openid).RetrieveUser();
    }
 
    protected void openid_ValidationFailed(object sender, EventArgs e)
    {
        // Validating the user has failed.  Respond appropriately.
    }
 
    protected void openid_SetupNeeded(object sender, EventArgs e)
    {
        // Immediate authentication response showed that the user isn't logged in.
        // You should redirect the user to OpenID Provider to continue setup.
        BeginAuth(false, true);
    }

}

OpenID Authentication Using Inline Handling (ASP.NET)

The older (and still compatible) method of using OpenIDConsumer, is looking at the current RequestedMode, and determining what needs to be done:

using ExtremeSwank.Authentication.OpenID;
 
public partial class _Default {
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = new OpenIDConsumer();
    openid.Identity = LoginBox1.Text;
    openid.BeginAuth();
  }
 
  protected void LogOutButton_Click(object sender, EventArgs e) {
    Session["OpenID_UserObject"] = null;
    // Handle user logout here
  }
 
  protected void Page_Load(object sender, EventArgs e) {
    if (!IsPostBack) {
      OpenIDConsumer openid = new OpenIDConsumer();
      switch (openid.RequestedMode) {
         case RequestedMode.IdResolution:
           if (openid.Validate()) {
             OpenIDUser thisuser = openid.RetrieveUser();
             Session["OpenID_UserObject"] = thisuser;
             // Authentication successful - Perform login here
           }
           else 
           {
             // Authentication failure handled here
           }
           break;
         case RequestedMode.CancelledByUser:
           // User has cancelled authentication - handle here
           break;
      }
    }
  }
}

Using OpenIDControl

As an alternative to using the class directly, consider using the OpenIDControl UserControl, which automatically handles everything for you:

  <%@ Register src="OpenIDControl.ascx" TagName="OpenIDControl" TagPrefix="uc1" %>  
  <form id="form1" method="get">
    <uc1:OpenIDControl runat="server" ID="OpenIDControl1" 
     RequiredFields="nickname,email" OptionalFields="dob,gender,fullname" 
     OnValidateSuccess="OpenID_ValidateSuccess" />
  </form> 

You can process the data received by hooking in to the OnValidateSuccess event:

  protected void LoginValidated(object sender, EventArgs e) {
    OpenIDControl openidcontrol = (OpenIDControl)sender;
    string UserOID = openidcontrol.UserObject.Identity;
    string BaseOID = openidcontrol.UserObject.BaseIdentity;
    string FullName = openidcontrol.UserObject.GetValue(SimpleRegistrationFields.FullName);
    string NickName = openidcontrol.UserObject.GetValue(SimpleRegistrationFields.Nickname);
    // Continue processing data
  }
  protected void Logout(object sender, EventArgs e) {
    // Perform some proprietary logout functions
  }

OpenIDControl supports the following events:

Working Outside ASP.NET

There are a few situations where the code may not be running in an ASP.NET environment. Here is simple example of creating static methods that implement a simple OpenID authentication check. You will likely make something a bit more complete in an actual implementation.

using System.Collections.Specialized;
using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Plugins.Extensions;

public class MyClass {

  private static OpenIDConsumer GetConsumer(NameValueCollection arguments)
  {
    // Initialize the Consumer in Stateless mode
    OpenIDConsumer openid = new OpenIDConsumer(arguments, null, null);
 
    // Initialize any required plug-ins here
  }
 
  public static string InitiateAuthentication(string identity) 
  {
    // Get a new OpenIDConsumer object.  Since we aren't responding to
    // a response, pass an empty NameValueCollection.
    OpenIDConsumer openid = GetConsumer(new NameValueCollection());
 
    // Set Identity to the supplied OpenID Identity
    openid.Identity = identity;
 
    // Discover the OpenID Provider from the Identity and
    // return the redirect URL for the browser.  Since we are
    // not in an ASP.NET session, we shouldn't try to automatically
    // redirect the user.
    return openid.BeginAuth(false, false);
  }
  
  // Confirm whether or not a HTTP request is a valid and positive authentication
  // assertion. You will need to pass the received arguments as a NameValueCollection,
  // which is the type of collection implemented by the Request object in ASP.NET.
  public static OpenIDUser HandleAuthResponse(NameValueCollection arguments) 
  {
    OpenIDConsumer openid = GetConsumer(arguments);
    OpenIDUser thisuser = null;
 
    switch (openid.RequestedMode) {
      case RequestedMode.IdResolution:
        // Validate the response.  If successful, populate "thisuser".
        if (openid.Validate()) 
        {
          thisuser = openid.RetrieveUser();
        }
        break;
        // Handle other cases as needed
    }
 
    // Return the retrieved user object.  If authentication 
    // failed, return null.
    return thisuser;
  }
}

To start authentication, you would:

  string url = MyClass.InitiateAuthentication("myname.myprovider.com");
  // Redirect the web browser to the URL in "url" here.  If "url" is null,
  // discovery was not successful.

To confirm an authentication response, you would:

  OpenIDUser user = MyClass.HandleAuthResponse(arguments);
  // Use the "user" object. If "user" is null, then the response did not
  // pass validation.

You will have to figure out what is needed to pass the redirect URL to the browser, and to pass the arguments from the request to the static method. Since an ASP.NET context is not available, OpenIDConsumer will not be able to automatically pull in that information.

Using Directed Identity

There are some situations where:

These requirements can be fulfilled by using the Directed Identity feature. In this mode, the OpenID Consumer will receive the user's OpenID from the OpenID Provider after the user has logged in.

You will have to know the URL of the OpenID Provider you want the user to log in to, and the OpenID Provider must support OpenID 2.0.

using ExtremeSwank.Authentication.OpenID;

public partial class _Default {
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = new OpenIDConsumer();
 
    // Enable Directed Identity
    openid.UseDirectedIdentity = true;
 
    // Use Yahoo! OpenID Provider
    openid.OpenIDServer = "https://open.login.yahooapis.com/openid/op/auth"
    openid.BeginAuth();
  }
  ...
}

Disabling Stateful Mode

OpenIDConsumer defaults to Stateful mode, which does more work at your site to keep network traffic low, and to be nicer to the OpenID Provider. In some cases, however, Stateful mode is not desired. You can disable it quite simply.

For ASP.NET environments:

  OpenIDConsumer openid = new OpenIDConsumer(null, null);

For non-ASP.NET environments:

  NameValueCollection arguments;
  OpenIDConsumer openid = new OpenIDConsumer(arguments, null, null);

Persisting Stateful Data

OpenIDConsumer defaults to Stateful mode, and keeps track of the needed data using the built-in ASP.NET Session and Application objects. This does not perform well in web garden or web farm environments, where different requests may be handled by different instances of the application, or on different servers in the environment.

You can save information to a central repository using the ISessionPersistence and IAssociationPersistence interfaces. There are several built-in classes that have already been created which use these interfaces, and are fairly easy to implement in your own code.

The example below uses the DbAssociationManager and DbSessionManager classes to implement stateful data persistence.

First, use the BuildDb() method to create the table that will store your associations. You will only need to do this once.

using ExtremeSwank.Authentication.OpenID.Persistence;
  
protected void SetupDatabase() 
{
  // Set up your database connection here
  IDbConnection conn = new MySqlConnection(connectionString);
 
  // Create the association manager using the connection string and a prefix that
  // will be applied to all table names
  DbAssociationManager assocmgr = new DbAssociationManager(conn, "Prefix_");
  assocmgr.BuildDb();
 
  // If you want to use database session persistence, set it up here
  // SessionID is some value that is unique to the user's session.
  DbSessionManager sessmgr = new DbSessionManager(conn, "Prefix_", sessionID);
  sessmgr.BuildDb();
}

Then, just use the OpenIDConsumer object normally, but create and use a DbAssociationManager instance:

using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Persistence;
 
public partial class _Default {
 
  public OpenIDConsumer InitConsumer()
  {
    // Set up your database connection here
    IDbConnection conn = new MySqlConnection(connectionString);
 
    // Create the association manager using the connection string and a prefix that
    // will be applied to all table names
    DbAssociationManager assocmgr = new DbAssociationManager(conn, "Prefix_");
 
    // If you want to use database session persistence, set it up here
    // SessionID is some value that is unique to the user's session.
    DbSessionManager sessionmgr = new DbSessionManager(conn, "_Prefix", sessionID);
 
    // Initialize the OpenIDConsumer object
    OpenIDConsumer openid = new OpenIDConsumer(assocmgr, sessionmgr);
 
    return openid;
  }
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = InitConsumer();
    openid.Identity = LoginBox1.Text;
    openid.BeginAuth();
  }
  ...
}

Simple Registration Extension

Simple Registration is a simple OpenID extension that provides for getting the most common information for website registration from the OpenID Provider.

using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Plugins.Extensions;
 
public partial class _Default {
 
  public OpenIDConsumer InitConsumer()
  {
    OpenIDConsumer openid = new OpenIDConsumer();
    SimpleRegistration sr = new SimpleRegistration(openid);
 
    // Get the user's full name, which is required
    sr.AddRequiredFields(SimpleRegistrationFields.FullName);
 
    // Get the user's e-mail address, which is optional
    sr.AddOptionalFields(SimpleRegistrationFields.Email);
 
    // Set the URL where your privacy policy is posted.
    // This may be presented to the user at the OpenID Provider.
    sr.PolicyURL = "http://myhost.com/Policy.html";
  }
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = InitConsumer();
    openid.Identity = LoginBox1.Text;
    openid.BeginAuth();
  }
  ...
}

When validation has succeeded, get the OpenIDUser object and collect the value(s):

  OpenIDUser user = openid.RetrieveUser();
  // Retrieve data using the same SchemaDefs, but retrieve using the alias
  string fullname = user.GetValue(SimpleRegistrationFields.FullName);
  string email = user.GetValue(SimpleRegistrationFields.Email);  

Attribute Exchange Extension

Attribute Exchange is a newer OpenID extension supported by some providers. It provides an interface to fetch and store values using schema namespaces.

A schema definition is a namespace URI and a configurable alias. For instance, a user's username can have the following namespace:

  http://openid.net/schema/namePerson/friendly

For the authentication request, we might use the alias "Username" to make it more easily accessible.

For convenience, most available namespaces and default aliases are available in the AttributeExchangeSchema static class. Each member consists of a SchemaDef object which includes both the namespace URI and a default alias.

Here is a fetch example:

using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Extensions;
 
public partial class _Default {
 
  public OpenIDConsumer InitConsumer()
  {
    OpenIDConsumer openid = new OpenIDConsumer();
    AttributeExchange ax = new AttributeExchange(openid);
    ax.Mode = AttributeExchangeMode.Fetch;
 
    // Get the user's full name, return only one value, and
    // tell the OpenID Provider that it is required
    ax.AddFetchItem(AttributeExchangeSchema.FullName, 1, true);
 
    // Get the user's website, request 2 values (user can 
    // have more than one site), and a response is optional
    ax.AddFetchItem(AttributeExchangeSchema.UrlWebsite, 2, false);
  }
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = InitConsumer();
    openid.Identity = LoginBox1.Text;
    openid.BeginAuth();
  }
  ...
}

When we're ready to retrieve the response, get the OpenIDUser object and collect the value(s):

  OpenIDUser user = openid.RetrieveUser();
  // Retrieve data using the same SchemaDefs, but retrieve using the alias
  string fullname = user.GetValue(AttributeExchangeSchema.FullName.Uri);
  string urls = user.GetValue(AttributeExchangeSchema.UrlWebsite.Uri);  
  // Both URLs are included in the same string, separated by ", "

You can also store values at the OpenID Provider, if supported by the Provider:

using ExtremeSwank.Authentication.OpenID;
using ExtremeSwank.Authentication.OpenID.Extensions;
 
public partial class _Default {
 
  public OpenIDConsumer InitConsumer()
  {
    OpenIDConsumer openid = new OpenIDConsumer();
    AttributeExchange ax = new AttributeExchange(openid);
    ax.Mode = AttributeExchangeMode.Store;
 
    // Set the user's full name
    ax.AddStoreItem(AttributeExchangeSchema.FullName, "Your Name");
 
    // Set the user's websites, one value for each
    ax.AddStoreItem(AttributeExchangeSchema.UrlWebsite, "http://mypage.com/", "http://mybizpage.com/"); 
  }
 
  protected void LoginButton_Click(object sender, EventArgs e) {
    OpenIDConsumer openid = InitConsumer();
    openid.Identity = LoginBox1.Text;
    openid.BeginAuth();
  }
  ...
}

Sign in to add a comment