I have a WCF service that is using a custom ServiceAuthorizationManager. The custom auth manager is already set up to handle Windows and Forms authentication.
However, if I connect with a client that is set to UserName auth, I can’t seem to find the username anywhere.
The client code looks like this:
this.ClientCredentials.UserName.UserName = 'user'; this.ClientCredentials.UserName.Password = 'pass'; this.Open(); this.MyMethod(); // my actual contract method this.Close();
Then on the server, I have my custom auth manager:
public sealed class AppAuthorizationManager : ServiceAuthorizationManager { public override bool CheckAccess(OperationContext operationContext, ref Message message) { // would like to check user/pwd here... } }
Is this possible?
- The
Thread.CurrentPrincipalis not set, operationContext.ServiceSecurityContext.PrimaryIdentityis not set.operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSetsis empty.
Is the user/pwd supposed to be available anywhere? Or do I have to add a custom UsernamePasswordValidator too?
Update: So I added a custom UserNamePasswordValidator and an IAuthorizationPolicy. My updated WCF config looks like this:
<behavior name='Server2ServerBehavior'> <serviceMetadata httpGetEnabled='true' /> <serviceDebug includeExceptionDetailInFaults='true' /> <serviceAuthorization principalPermissionMode='Custom' serviceAuthorizationManagerType='MyApp.AuthManager, MyApp'> <authorizationPolicies> <add policyType='MyApp.TokenAuthorizationPolicy, MyApp' /> </authorizationPolicies> </serviceAuthorization> <serviceCredentials> <userNameAuthentication customUserNamePasswordValidatorType='MyApp.PFUserNameValidator, MyApp' /> </serviceCredentials> </behavior>
If I set a breakpoint in all 3 of those classes, WCF throws the exception:
LogonUser failed for the 'username' user. Ensure that the user has a valid Windows account. at System.IdentityModel.Selectors.WindowsUserNameSecurityTokenAuthenticator.ValidateUserNamePasswordCore(String userName, String password)
Before any of them are run. Hmmm…
This is normally handled in the UsernamePasswordValidator – which is the only place you’ll have access to the password. However, this isn’t where you set the principal – that would be in the
IAuthorizationPolicy‘sEvaluatemethod, which might look something like:(where
TrustedAuthTypeis the name of our password validator)With this in place, the thread’s principal will be set, and we can identify ourselves (and use roles-based security etc)