WCF Services Sample: Authenticate Silverlight Client based on Custom Security Token

yuzhangqi發表於2010-06-02

In my blog "WCF Services Sample: Authenticate Silverlight Client based on UserName and Password", I show you how to improve security of WCF security by using a custom validator to authenticate Silverlight client based on username and password.

That solution look good. However, it is not a final solution. You know, the Silverlight application runs on local machine of the remote users. The Silverlight communicate with WCF service via BasicHttpBinding, which transfer messages in cleratext, include username and password. In HTTPS scenario, it is secure in some degree. but in HTTP scenario the security is very very poor.

So we have to resort to better solution.

Because BasicHttpBindign does NOT give support on message encryption, I think if it is possible to generate a custom security token based on username and a timestamp, then inject this token into message header of WCF service.

Yes, it is possible to do so. WCF provides us with more extensibility. To learn how to inject data into message header and inspect it on service side, refer to my blog <WCF Extension : Inject and Inspect Custom Message>.

1. Revisit WcfSecurityTokenMessageInspector class

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{ int index = request.Headers.FindHeader("SecurityToken", "");
if (index >= 0) { string token = request.Headers.GetHeader(index);

// validate the security token here.... }

return null; }

In the method AfterReceiveRequest() we retrieve the custom message header "SecurityToken". Then authenticate based on the security token. In a real application, the authentication procedure may consists of: 1) decrypt the security token because it has been encrypted. 2) parse the decrypted security token string and retrieve the caller identity such as username,password,timestamp etc. 3) compare the identity with those in the persistent store such as database,Active Directory to confirm if it is authenticated. 4) if authentication suceeds then continue,else throw FaultException to make the WCF service return error message to the caller.

You may remember I have introduced 2 choice for authentication : one is username/password in cleartext, another is a encrypted security token. The WCF client may be any application: Silverlight application, ASP.Net web application, other WCF service, and even applications such as COM,Java. We do not know what the client is. That's to say we can not mandate our WCF service to authenticate on client Credential or custom security token exclusively.

The main idea here is to check custom security token first, if the security token exists then validate it. if the security token does not exist, then check the ClientCredential.UserName and ClientCredential.Password, and validate it. The code looks like below.

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
int index = request.Headers.FindHeader("SecurityToken", "");
User user;
if (index >= 0)
{
user = ValidateSecurityToken(request, index);
}
else
{
user = ValidateUserNameCredential(request);
}
return null;
}

private static User ValidateUserNameCredential(Message request)
{
if (request.Properties.Security != null)
{
UserNameSecurityToken securityToken =
request.Properties.Security.IncomingSupportingTokens[0].SecurityToken as UserNameSecurityToken;
string fullUserName = string.Empty;
string password = string.Empty;

if (securityToken != null)
{
fullUserName = securityToken.UserName;
password = securityToken.Password;
}
string userName;
string domain;
StringTools.ParseFullUserName(fullUserName, out userName, out domain);

AuthenticationService auth = new AuthenticationService();

return auth.AuthenticateUserNameCredential(userName, password, domain);
}
throw new FaultException("No user information specified.");
}
private static User ValidateSecurityToken(Message request,int index)
{
string token = request.Headers.GetHeader(index);

if (!string.IsNullOrEmpty(token))
{
string message;

AuthenticationService auth = new AuthenticationService();

return auth.AuthenticateSecurityToken(token, out message);

} throw new UnauthorizedAccessException("Your user identity is invalid.");
}

2. Revisit Web.config







































userNamePasswordValidationMode="Custom"/>




Now our WCF service supports HTTP and HTTPS, and can validate on ClientCredential or custom security token.

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/13651903/viewspace-1034085/,如需轉載,請註明出處,否則將追究法律責任。

相關文章