WCF: IAuthorizationPolicy
Back to the beginning
From the early period of .net 1.0 CAS guys told us that imperative and declarative security are a good thing. Writing this kind of code is really important:
we have learned that code execution policies and code access security prevents the execution of that method if prerequisites expressed by the attribute are not met.[PrincipalPermission( SecurityAction.Demand, Authenticated = true, Role = "Managers" )] public void ReallySecureMethod() { //something that only "Managers" can do }
So?
If you try to apply the attribute to a WCF operation you always get a security exception basically because the current principal never meets the security assertions expressed by the permission attribute, the reason is fairly simple: when it comes to services the concept of principal is not so clear in the end, at the service level there are at least 2 different possible principal:
- the user running the code: e.g. if you are running inside IIS the application pool identity;
- the user the calls the WCF operation;
Uhm…
Have you ever tried WIF (Windows Identity Foundation)? If you tried it you noticed that the above code works fine, the WCF service instance has a valid current principal out-of-the-box that matches the current claim identity.
Why?
Basically WIF ads a custom authorization policy to the authorization policies pipeline of WCF. What the hell is the authorization policies pipeline?
Authorization policies in WCF are an extension point that lets you take custom decisions about security, they are called in an early stage of the WCF operation call stack so you can do a lot of different thing in this stage but as the name implies they are thought for authorization purpose. Policies are handled in a first come first served manner, following the order in which policies are added to the WCF endpoint behavior configuration.
An authorization policy is class that implements the IAuthorizationPolicy interface, the implementation is trivial and the only point of interest is the “Evaluate” method:
…what are we doing?public bool Evaluate( EvaluationContext evaluationContext, ref object state ) { if( !evaluationContext.ContainsIdentity() ) { evaluationContext.SetPrincipal( Helper.GetAnonymousIdentity() ); return true; } return false; }
- first we check if the current call contains any identity information (ContainsIdentity is an extension method that deals with WCF evaluation context properties that contains the identities list);
- if none is found we setup (SetPrincipal is another extension method) an anonymous identity that suites our business logic needs and return true;
- Otherwise we return false;
Adding policies is really easy:
After the stack execution we are sure that the current principal has a value that suites our business needs and that meets the CAS requirements that let us write declarative security.<behavior name="">
<serviceMetadata … />
<serviceDebug … />
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="MyWcfAuthorizationPolicy, MyExtensions" />
<add policyType="MyAnonymousAuthorizationPolicy, MyExtensions" />
authorizationPolicies>
serviceAuthorization>
behavior>
Cool
.m