My favorites | Sign in
Project Logo
                
Search
for
Updated Feb 28, 2009 by j...@extremeswank.com
Labels: Featured
UsingDesktopConsumer  
Examples for successfully using OpenIdDesktopClient for non-web environments

About OpenIdDesktopClient

OpenIdDesktopClient includes a set of services used to provide OpenID Authentication services to non-web applications. It utilizes OpenIdClient for authentication, resulting in full compatibility when extension plug-ins are needed.

The end-user experience is seamless. The user is prompted for their OpenID, then a web browser opens at their workstation so they can authenticate with their provider. The authentication response is automatically received by the application, and the web browser is closed. After successful authentication, the application works normally.

If you want to know more detail about the internals, see the "How it Works" section below for additional detail.

Usage Example

First, we need to initialize OpenIdDesktopClient, passing the OpenID we want to check, and (at minimum), the amount of time we want to wait before timing out. We can then register all the required extension plug-ins.

The important piece is either subscribing to three important events, or calling RetrieveAuthenticationResponse(). RetrieveAuthenticationResponse() will block until a response is received, or the timeout has expired.

If you prefer blocking to wait for the response, you can use the following example:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ExtremeSwank.OpenId;
using ExtremeSwank.OpenId.PlugIns.Extensions;

namespace MyProgram
{
    public class Program
    {
        static void Main(string[] args)
        {
            OpenIdDesktopClient oidc = new OpenIdDesktopClient("extremeswank.com", 60);

            // Optionally load an Extension plug-in if more functionality is needed
            SimpleRegistration sr = new SimpleRegistration(oidc.Consumer);
            sr.AddRequiredFields(SimpleRegistrationFields.FullName);

            Uri url = oidc.BeginAuthentication();
            if (url != null)
            {
                // Running Process.Start() here is useful for demonstration purposes only, 
                // as it will launch the default web browser wherever this code is running.
                // In a client/server scenario, you will pass the value of "url" to the 
                // client, which should open a web browser locally.
                Process.Start(url.AbsoluteUri);

                // Wait until a response is received, and get whether or not
                // authentication is successful
                bool isValid = oidc.RetrieveAuthenticationResponse();
                if (!isValid)
                {
                    // Validation failed, get the current error condition.
                    Console.WriteLine("Validation failed!");
                    Console.WriteLine(oidc.Error);
                }
                else
                {
                    // Validation succeeded, retrieve the OpenIDUser object
                    // and retrieve any requested extension data
                    Console.WriteLine("Validation succeeded!");
                    OpenIdUser user = oidc.Consumer.RetrieveUser();
                    Console.WriteLine(user.Identity);
                    Console.WriteLine(user.GetValue(SimpleRegistrationFields.FullName));
                }
            }
            else
            {
                // Discovery of the OpenID failed.  Either the user mistyped it,
                // or a communication error occurred.
                Console.WriteLine(oidc.Error);
            }
            Console.ReadLine();
        }
    }
}

In the example below, the event method is used. This allows us to continue processing while we are waiting for a response.

using System;
using System.Diagnostics;
using ExtremeSwank.OpenId;
using ExtremeSwank.OpenId.PlugIns.Extensions;

namespace MyProgram
{
    class Program
    {
        static bool _DoneAuthenticating;
        static bool _Debug = false;

        static void Main(string[] args)
        {
            // If _Debug is set to true, listen for trace events and write
            // them to the console.
            if (_Debug)
            {
                Messenger m = new Messenger();
                Trace.Listeners.Add(m);
            }

            // Write welcome message to the console
            Console.WriteLine("Welcome to XXXX.  Please log in.");

            // Get the OpenIDConsumer
            OpenIdDesktopClient oidc = GetOpenID();

            // Get the redirect URL and start the temporary HTTP server
            Uri url = oidc.BeginAuthentication();
            if (url != null)
            {
                // Start the web browser local to this code.
                // This should be done at the client in client/server apps.
                Process.Start(url.AbsoluteUri);
            }
            else
            {
                // An error occurred
                Console.WriteLine(oidc.Error);
                _DoneAuthenticating = true;
            }
            InteractWithUser(oidc);
        }

        static OpenIdDesktopClient GetOpenID()
        {
            // Initialize the oidc variable
            OpenIdDesktopClient oidc;

            // We are going to prompt the user for their OpenID
            // and check its validity.  If its not valid,
            // then repeat the process until a valid OpenID is
            // entered.
            while (true)
            {
                // Write the prompt to the console
                Console.Write("OpenID: ");

                // Get the user's response
                string id = Console.ReadLine();

                // If id is null, just loop through again without
                // feedback.
                if (!String.IsNullOrEmpty(id))
                {
                    // Create a new OpenIDDesktopConsumer using the supplied ID,
                    // and a 60 second timeout.  The rest of the options will
                    // be set to defaults.
                    oidc = new OpenIdDesktopClient(id, 60);

                    // Initialize a SimpleRegistration plugin
                    SimpleRegistration sr = new SimpleRegistration(oidc.Consumer);
                    sr.AddRequiredFields(SimpleRegistrationFields.FullName);

                    // Because we are doing this asynchronously, we need to listen for the
                    // events that could occur
                    oidc.AuthenticationSuccessful += new EventHandler(oidc_AuthenticationSuccessful);
                    oidc.AuthenticationResponseTimedOut += new EventHandler(oidc_AuthenticationResponseTimedOut);
                    oidc.AuthenticationFailed += new EventHandler(oidc_AuthenticationFailed);

                    // Do a discovery on the ID to confirm that its valid.
                    // If the ID is valid, return with the current OpenIDDesktopConsumer object.
                    if (oidc.Consumer.IsValidIdentity())
                    {
                        break;
                    }

                    // ID was not valid, loop through again
                    Console.WriteLine("Error Code: " + oidc.Error);
                    Console.WriteLine("Unable to discover OpenID.  Please check your spelling and try again.");
                }
            }
            return oidc;
        }

        static void InteractWithUser(OpenIdDesktopClient oidc)
        {
            // We want to keep the application running until a
            // response has been received.  We do this by
            // continually waiting for user input.
            while (true)
            {
                // Block until input has been entered
                string c = Console.ReadLine();

                // If a response has been received, or Timeout
                // has occurred, it's safe to stop processing.
                if (_DoneAuthenticating) { break; }

                // If still waiting for the response and the
                // user types "cancel", cancel everything
                // and stop processing
                if (c.ToLower() == "cancel")
                {
                    oidc.CancelAuthentication();
                    break;
                }
            }
        }

        static void oidc_AuthenticationFailed(object sender, EventArgs e)
        {
            OpenIdDesktopClient oidc = (OpenIdDesktopClient)sender;
            Console.WriteLine("Validation failed!");
            Console.WriteLine(oidc.Error);
            _DoneAuthenticating = true;
        }

        static void oidc_AuthenticationSuccessful(object sender, EventArgs e)
        {
            OpenIdDesktopClient oidc = (OpenIdDesktopClient)sender;
            Console.WriteLine("Validation succeeded!");
            OpenIdUser user = oidc.Consumer.RetrieveUser();
            Console.WriteLine(user.Identity);
            Console.WriteLine(user.GetValue(SimpleRegistrationFields.FullName));
            _DoneAuthenticating = true;
        }

        static void oidc_AuthenticationResponseTimedOut(object sender, EventArgs e)
        {
            OpenIdDesktopClient oidc = (OpenIdDesktopClient)sender;
            Console.WriteLine("Authentication response timed out!");
            _DoneAuthenticating = true;
        }
    }

    public class Messenger : TraceListener
    {
        public override void Write(string message)
        {
            Console.Write(message);
        }

        public override void WriteLine(string message)
        {
            Console.WriteLine(message);
        }
    }
}

Stateless vs. Stateful Mode

By default, OpenIdDesktopClient works in Stateless mode. This reduces the complexity of your application by not saving any sort of state between authentication requests. If you have a large number of users using your application, and you expect to have many of them using the same OpenID Provider, Stateful authentication is a good idea.

You have two options. For the default mode, use EnableStatefulMode(). For a more performant implementation, use EnableStatefulMode(assocmgr, sessionmgr).

How it Works

When you initialize OpenIdDesktopClient, it initializes a copy of OpenIdClient, and sets up all the variables it needs. When oidc.BeginAuthentication() is called, a temporary HTTP server is loaded on a random port number between 1024 and 5000 (you can manually set this if needed), and the redirect URL for the web browser is returned.

At this point, a web browser should be started wherever the user is located, which is completely up to you. This will allow the user to authenticate with their OpenID Provider. Upon authentication, the web browser will automatically redirect back to the temporary HTTP server, with the authentication response.

Once received, the authentication response is verified. The application should then check RetrieveAuthenticationResponse() to see if the user is successfully authenticated.

You can then retrieve the OpenIdUser object to get additional details and any requested extension data.


Comment by grpmpk, May 07, 2008

In a client/server environment, are all the examples above meant for the service side (where the return value of oidc.BeginAuthentication?(); are passed to the client) or are all examples client side?

Comment by j...@extremeswank.com, Feb 28, 2009

grpmpk: In a client/server scenario, pass the URI from BeginAuthentication? to the client, and have the client open the web browser for authentication. Once authentication completes, the browser will redirect back to the temporary HTTP server running at your server.


Sign in to add a comment
Hosted by Google Code