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; } } |