I have a working custom UserNamePasswordValidator that calls into my Oracle DB.
This class derives from System.IdentityModel.Selectors.UserNamePasswordValidator and
I'm not a WCF expert, but from what I've read and implemented so far, the 'correct' way to do this would be to use the Validator to authenticate the user, and then implement an IAuthorizationPolicy to do the actual authorization. So it would be in the authorization policy that you'll set your custom principal on the current thread.
To be able to forward information from the username/password validation, you can implement a security token authenticator that inherits from UserNameSecurityTokenAuthenticator. The SecurityTokenAuthenticator will first call the validator and if validation succeeds, it can add your custom authorization policy and send userinfo to the policy through the constructor. Something a long the lines of this:
public class CustomUsernameSecurityTokenAuthenticator : UserNameSecurityTokenAuthenticator
{
protected override bool CanValidateTokenCore(System.IdentityModel.Tokens.SecurityToken token)
{
return (token is UserNameSecurityToken);
}
protected override ReadOnlyCollection ValidateTokenCore(SecurityToken token)
{
var authorizationPolicies = new List();
try
{
var userNameToken = token as UserNameSecurityToken;
new CustomUserNameValidator().Validate(userNameToken.UserName, userNameToken.Password);
var claims = new DefaultClaimSet(ClaimSet.System, new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));
authorizationPolicies.Add(new CustomAuthorizationPolicy(claims));
}
catch (Exception)
{
authorizationPolicies.Add(new InvalidAuthorizationPolicy());
throw;
}
return authorizationPolicies.AsReadOnly();
}
}
There's an article here that describes a bit more around the involved classes; http://blogs.msdn.com/card/archive/2007/10/04/how-identity-providers-can-show-custom-error-messages-in-cardspace.aspx