The Custom SOAP Extension Implementation

Listing 1. This code shows the SOAP extension implementation that enforces the role-based security policy based on the caller credentials in the WS-Security message header.

/// <summary>
/// The SOAP extension implementation
/// that provides role-based
/// security information
/// from the WS-Security message header.
/// </summary>
public class AuthorizedRolesExtension
   : SoapExtension
   {
   private string[] roles = null;
   private string roleString = null;
   private string methodName = null;

   /// <summary>
   /// The method that processes the
   /// SOAP message and looks
   /// for the WS-Security User token.
   /// </summary>
   /// <param name="message">The SOAP message</param>
   public override void ProcessMessage (SoapMessage message)
   {
      if (message.Stage == SoapMessageStage.AfterDeserialize)
      {         
      SoapContext ctxt = 
         RequestSoapContext.Current;
      foreach (SecurityToken tok 
             in ctxt.Security.Tokens)
      {
         // Only interested in
         // user name tokens for
         // this sample implementation.
         if (tok is UsernameToken)
         {
         UsernameToken user =
            (UsernameToken)tok;

         // See the comments on the
         // GetRoles method.
         string[] userRoles =  
            GetRoles(user.Username);

         bool isAuthorized = false;

         // Allow anonymous and all
         // access levels through.
         if(roles.Length == 1 
            && (roles[0].Equals("*")
            || roles[0].Equals("?")))
         {            
            isAuthorized = true;
         }
         else
         {
            // Match the roles.
            foreach (string role
                in roles)
            {
            foreach(string userRole
                  in userRoles)
            {
               if(role.Equals(userRole))
               {
               isAuthorized = true;
               break;
               }
            }
            if(isAuthorized)
               break;
            }
         }

         // Still not authorized.
         if(!isAuthorized)
         {
            throw new SoapException(
            "Unauthorized Access to "
            + methodName
            + " by "
            + user.Username,
            SoapException.ClientFaultCode);
         }
         GenericIdentity id =
            new GenericIdentity(
               user.Username);
         GenericPrincipal p = 
            new GenericPrincipal(
               id,userRoles);
         HttpContext.Current.User = p;

         return;
         }
      }
      // No user token.
      // Check to see
      // if anonymous access
      // is allowed.
      if(roles.Length == 1
         && roles[0].Equals("?"))
      {
         return;
      }

      // End of method.
      // Not authorized.
      throw new SoapException(
        "Unauthorized [Anonymous] Access to " 
         + methodName,
         SoapException.ClientFaultCode);
      }
   }

   /// <summary>
   /// Returns an array of roles permitted
   /// for the given user.
   /// Override this method in your implementation
   /// to do something more "real-world."
   /// </summary>
   /// <param name="username">
   /// the username to get the roles for
   /// </param>
   /// <returns>an array of roles</returns>
   protected virtual string[] GetRoles(
string username)
   {
      if(username.Equals("Bob"))
      return new string[]{"Guest"};
      else if(username.Equals("Cathy"))
      return new string[]{"Manager"};
      else
      return new string[0];
   }

   /// <summary>
   /// This method is not implemented
   /// </summary>
   /// <param name="type"></param>
   /// <returns></returns>
   public override Object GetInitializer (
Type type)
   {
      return GetType ();
   }

   /// <summary>
   /// Iniitializes the SOAP Extension
   /// </summary>
   /// <param name="info"></param>
   /// <param name="attribute"></param>
   /// <returns></returns>
   public override Object GetInitializer (
      LogicalMethodInfo info,
      SoapExtensionAttribute attribute)
   {
      return new InitObject(info,attribute);
   }

   /// <summary>
   /// Iniitializes the SOAP Extension
   /// </summary>
   /// <param name="initializer"></param>
   public override void Initialize (
Object initializer)
   {
      InitObject o = 
initializer as InitObject;
      if(o != null)
      {
      roleString = 
   ((AuthorizedRolesAttribute)o.attr).Roles;
      roles = roleString.Split(',');
      string assemblyName =
         o.methodInfo.MethodInfo.DeclaringType.ToString();
      assemblyName =
         assemblyName.Substring(assemblyName.LastIndexOf(".")+1);
      methodName =
         assemblyName + "::" + o.methodInfo.MethodInfo.Name;
      }
   }
   }

   class InitObject
   {
   public LogicalMethodInfo methodInfo;
   public SoapExtensionAttribute attr;

   public InitObject(
      LogicalMethodInfo methodInfo,
      SoapExtensionAttribute attr)
   {
      this.methodInfo = methodInfo;
      this.attr = attr;
   }
}