none
Retain information in WCF web service recieved during custom validation RRS feed

  • Question

  • Hi,

    I have a WCF service that wraps access to a legacy platform. The request includes username/password in the soap header that I have implemented a custom 'UserNamePasswordValidator' to handle.

    custom login validator Code:

    public class CustomAuthenticator : UserNamePasswordValidator
    {
        /// <summary>
        /// Performs authentication against Admin.
        /// </summary>
        /// <param name="userName">username to authenticate</param>
        /// <param name="password">password to authenticate</param>
        public override void Validate(string userName, string password)
        {
            if (null == userName || null == password)
            {
                throw new ArgumentNullException();
            }        

             LoginResponse ls = AdminGateway.Login(userName, password)

            if (ls.loginSuccess != true)
            {
                throw new FaultException("Login credentials invalid.");
            }
        }
    }
     

    In the above example the 'AdminGateway.Login' static method is called which in turn calls a pre-existing stored procedure that attempts the login and returns a number of required id's and login result (loginSuccess) in the object of type LoginResponse.

    The problem I have is that I need to keep the LoginResponse object's data around and accessable by my service for use later. How can I do this?

    I am hoping there is a simple solution to this as I am not that experienced with WCF but I am stuggling to find it.

    My first idea was to create a static class / singleton that had properties that I could set then use later. But I have to consider that this service is likly to have multiple calls executing at the same time which I wasnt sure weather would work. How is static classes instanced? will there be one instance per call or one instance for all calls?

    All help, advice and best practices very welcome on this!

    Kind Regards

    Stephen.

    Tuesday, February 23, 2010 3:55 PM

Answers

  • Hi Stephen,

    In order to prevent leaking the client security info to service context, the validation method is running on a separate thread. So we can not pass the LoginResponse to service directly.

    One possible way would be store the loginResponse in a static Dictionary, use username as key. In service operation, we could get the username by accessing ServiceSecurityContext.
       OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name

    Then, we could use the username to fetch the loginresponse from Dictionary.
    Here is my sample code

    namespace CustomUserNameAuthentication_WCF
    {
        public class MyCustomValidator:UserNamePasswordValidator
        {
            public override void Validate(string userName, string password)
            {
                if (!userName.Equals(password))
                    throw new SecurityTokenException("Username need to be the same with password");
                else
                    AuthenticationDictionary.Dictionary[userName] = password;
            }
        }

        public class AuthenticationDictionary
        {
            public static Dictionary<string, string> Dictionary;
            static AuthenticationDictionary()
            {
                Dictionary = new Dictionary<string, string>();
            }
        }
    }

        public class Service1 : IService1
        {
            public string GetData(int value)
            {
                var username = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
                var pwd = AuthenticationDictionary.Dictionary[username];

                return string.Format("You entered: {0}", value);
            }
       }


    Thanks,


    Mog Liang
    • Marked as answer by StephenW11 Monday, March 1, 2010 5:10 PM
    Thursday, February 25, 2010 5:35 AM

All replies

  • Hi Stephen,

    In order to prevent leaking the client security info to service context, the validation method is running on a separate thread. So we can not pass the LoginResponse to service directly.

    One possible way would be store the loginResponse in a static Dictionary, use username as key. In service operation, we could get the username by accessing ServiceSecurityContext.
       OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name

    Then, we could use the username to fetch the loginresponse from Dictionary.
    Here is my sample code

    namespace CustomUserNameAuthentication_WCF
    {
        public class MyCustomValidator:UserNamePasswordValidator
        {
            public override void Validate(string userName, string password)
            {
                if (!userName.Equals(password))
                    throw new SecurityTokenException("Username need to be the same with password");
                else
                    AuthenticationDictionary.Dictionary[userName] = password;
            }
        }

        public class AuthenticationDictionary
        {
            public static Dictionary<string, string> Dictionary;
            static AuthenticationDictionary()
            {
                Dictionary = new Dictionary<string, string>();
            }
        }
    }

        public class Service1 : IService1
        {
            public string GetData(int value)
            {
                var username = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
                var pwd = AuthenticationDictionary.Dictionary[username];

                return string.Format("You entered: {0}", value);
            }
       }


    Thanks,


    Mog Liang
    • Marked as answer by StephenW11 Monday, March 1, 2010 5:10 PM
    Thursday, February 25, 2010 5:35 AM
  • That should work just fine thank you :)

    regards,

    Stephen.

    Monday, March 1, 2010 5:09 PM
  • Your code saved my day.

    Thank you very much

    Regards,Suvasish Das

    Friday, March 30, 2012 7:37 PM