Varying WCF Security Roles/Claims by Method Parameter
I have a class that implements IAuthorizationPolicy. I set up a custom Principal object based on the logged in user which has all of my base level roles (I have also done this using claims). Now I would like to change the roles that a particular principal has depending on a key value passed in as a message parameter.
The problem I am having is that the request message cannot be read in the authorization policy class because I don't have access to write the message back to the request context. I c开发者_如何学Goan copy and read the message in a ServiceAuthorizationManager derived class using an override of the CheckAccess method. However, I have to ensure that the GetAuthorizationPolicies method has already been called prior to doing that.
I am looking for suggestions on how I can vary the roles on a principal, based on whether or not the message contains a particular parameter. Basically, when the Evaluate method id called on the policy I want to do something like this:
string myObjectId = null;
if (!messageCopy.IsEmpty)
{
System.Xml.XmlDictionaryReader xdr = messageCopy.GetReaderAtBodyContents();
xdr.ReadToDecendant("objectId");
if (xdr.Read())
{
myObjectId = xdr.ReadContentAsString();
}
xdr.Close();
}
messageCopy.Close();
ClaimSet claims = (myObjectId != null) ?
MapClaims(identity, myObjectId) : MapClaims(identity);
DefaultPrincipal principal = new DefaultPrincipal(identity, claims);
After an entire day of attempted failures, I gave up on trying to read the message body and used an easier method, adding a SOAP message header. When calling the service I now perform the following:
using (new OperationContextScope((IContextChannel)myService)) {
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader("objectId", "http://tempuri.org/", "object value"));
myService.BeginMyOperation(parm, callback, state);
}
Then in my service authorization policy's Evaluate method I do this:
int index = OperationContext.Current.IncomingMessageHeaders.FindHeader(
"objectId", "http://tempuri.org/");
string myObjectId = (index < 0) ? null :
OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index);
ClaimSet claims = (myObjectId != null) ?
MapClaims(identity, myObjectId) : MapClaims(identity);
DefaultPrincipal principal = new DefaultPrincipal(identity, claims);
I run into the same situation while developing WebAPI security and I choosen the next approach:
- Method that recieves argument creates AuthorizationContext where it passes the argument as Resource claim
- My custom ClaimsAuthorizationManager then can get argument from AuthorizationContext.Resource and use it from authorization.
精彩评论