phramusca
phramusca

Reputation: 123

UserNamePasswordValidator send custom error message to client

I have a custom user validator implementing UserNamePasswordValidator. This validator is calling another authentication web service using WCF to validate the user.

It works fine, but I'd like to throw a custom message to the final client in case the authentication service call (on middle server side) fails for some reason (FaultException, CommunicationException, TimeoutException or any other Exception).

All I am getting on the client is always the same message popup telling that authentication Basic failed.

How can I throw a custom message back to the client (as a FaultException or any other way) ?

class CustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        try {
            string domain="";
            string userNameOnly;

            //Parse userName to extract domain and userNameOnly
            if(userName.Contains('\\')) {
                String[] splitted = userName.Split('\\');
                domain = splitted[0];
                userNameOnly = splitted[1];
            }
            else {
                userNameOnly = userName;
            }

            //throw new FaultException("Test fault exception from CustomUserNameValidator");

            //Get the authentication service
            ServiceReference1.AuthWSClient service = new ServiceReference1.AuthWSClient("AuthWSPort");

            //Call the athentication service
            ServiceReference1.user user = service.connect(domain, userNameOnly, password); 

            //TODO: Catch exceptions (invalid user throws one)
            //throw new SecurityTokenValidationException("Authentication failed for \"" + userName + "\"");
        }
        catch (FaultException ex)
        {
            //throw new FaultException("Authentication service (called from ATLAS server) returned an error: \n\n" + ex.Message);
            throw new SecurityTokenValidationException("Authentication service (called from ATLAS server) returned an error: \n\n" + ex.Message);
        }
        catch (CommunicationException ex)
        {
            //throw new FaultException("Communication issue with authentication service (called from ATLAS server): \n\n" + ex.Message);
            throw new SecurityTokenValidationException("Communication issue with authentication service (called from ATLAS server): \n\n" + ex.Message);
        }
        catch (TimeoutException ex)
        {
            //throw new FaultException("Connection with authentication service (called from ATLAS server) has timed out: \n\n" + ex.Message);
            throw new SecurityTokenValidationException("Connection with authentication service (called from ATLAS server) has timed out: \n\n" + ex.Message);
        }
        //catch (Exception ex)
        //{
        //    //Unexpected exception
        //    log.LogError(ex.ToString());
        //    throw;
        //}
    }
}

The client has similar try/catch block, but looks like it is not used for UserNamePasswordValidator: there seems to be a specific WCF internal catch for errors from UserNamePasswordValidator.

Upvotes: 1

Views: 1051

Answers (1)

tooomg
tooomg

Reputation: 469

When throwing an exception from the Validate method of a UserNamePasswordValidator, the exception is wrapped as the InnerException of a MessageSecurityException (from System.ServiceModel.Security package), which is the type you have to catch client-side:

try
{ ... }
catch (MessageSecurityException e)
{
    Exception exc = e.InnerException;
    // Process "exc" here, depending of its type
}

I hope it will help.

Upvotes: 1

Related Questions