Custom Authentication Process

The actions to execute after a successful federated SignOn or Logout can be customized as necessary to accommodate special use cases. Understanding the Default Authentication Process is a good idea before extending this process.

The most common use case is to replace the FormsAuthenticationAction with a custom implementation. For instance, if the identity provider does not provide a NameIDFormat which can be easily mapped to a local user, but does provide attributes that are, then the FormsAuthenticationAction can be replaced with a custom MyAuthenticationAction.

There are two steps to do this.

Create a New Action

Creating a new action is as simple as inheriting from SAML2.Actions.IAction and implementing your custom authentication scheme. Below is an example of such an implementation, which identifies local users by a RequestedAttribute that the identity provider has passed back instead of the default <Subject>.

    public class MyAuthenticationAction : IAction
    {
        #region Implementation of IAction

        private string _name = "MyAuthentication";

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Action performed during login.
        /// </summary>
        /// <param name="handler">The handler initiating the call.</param>
        /// <param name="context">The current http context.</param>
        /// <param name="assertion">The saml assertion of the currently logged in user.</param>
        public void SignOnAction(AbstractEndpointHandler handler, HttpContext context, Saml20Assertion assertion)
        {
            // Ensure that the necessary attributes have been returned
            if (!Saml20Identity.Current.HasAttribute("identifier"))
            {
                throw new ArgumentException("SAML Response did not contain the identifier attribute.");
            }

            // Ensure that there is a value passed back for identifier
            if (!Saml20Identity.Current["identifier"].Any(x => x.AttributeValue.Length > 0))
            {
                throw new FormatException("SAML Response contained the identifierattribute, but did not include a value.");
            }

            var identifier = Saml20Identity.Current["identifier"].FirstOrDefault(x => x.AttributeValue.Length > 0).AttributeValue.FirstOrDefault();
            var user = LookupUserByIdentifier(identifier);

            // Check for existing user
            if (user == null)
            {
                context.Response.Redirect(url.Action("AccessDenied", "Error"));
            }

            // Sign in
            FormsAuthentication.SetAuthCookie(user.Name, false);  
        }

        /// <summary>
        /// Action performed during logout.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="context">The context.</param>
        /// <param name="IdPInitiated">During IdP initiated logout some actions such as redirecting should not be performed</param>
        public void LogoutAction(AbstractEndpointHandler handler, HttpContext context, bool IdPInitiated)
        {
            FormsAuthentication.SignOut();
        }

        #endregion

        ...
    }

Replacing Action in Configuration

To enable the custom authentication action instead of the FormsAuthenticationAction, the <actions> element must be added / modified to override the defaults.

  <saml2>
    ...
    <actions>
      <clear/>
      <action name="SetSamlPrincipal" type="SAML2.Actions.SamlPrincipalAction, SAML2" />
      <action name="MyAuthentication" type="MyProject.MyAuthenticationAction, MyProject" />
      <action name="Redirect" type="SAML2.Actions.RedirectAction, SAML2" />
    </actions>
    ...
  </saml2>

Summary

In summary, it easy to override the default behavior to accommodate custom authentication workflows. In this case, the <Subject> is completely ignored, and the attributes passed back are used to find a local identity. This action could just as easily be extended to automatically create a user if they don't exist, etc.

Last edited Aug 15, 2013 at 6:06 PM by i8beef, version 6

Comments

No comments yet.