In the previous article, I’ve presented information about Security Token Service (STS). We know how to build sample Active STS and Relying Party Application. In this article, we focus on sample service based on WCF (Windows Communication Foundation), as we will only try to build sample service with claims-based authentication and authorization. All technical aspects connected with security, e.g., configuration, certificates, encryption, signature or CRL will be described in detail in the next posts.
WCF “ABC”
Windows Communication Foundation (WCF) is a Microsoft framework for building service-oriented applications. “ABC
" is the WCF mantra. "ABC
" is the key to understanding how a WCF service endpoint is composed.
Figure 1. WCF ABC
- The Address specifies where the service is residing.
- The Binding is how the service is to be used. The Binding specifies (protocol to use, encoding to use, type of security requirements to be used, such as SSL or SOAP message security)
- The Contract identifies operations exposed by the service.
WCF and WIF
WCF provides easy integration with WIF, which allows to use WIF’s features, such as the new claims model, support for additional security token types and token handling in WCF services. For integration with WIF, WCF offers dedicated binding WS2007FederationHttpBinding.
How to Build WCF Service with Claims-based Authentication and Authorization
In this article, we try to build WCF with claims-based authentication and authorization mechanism. Thanks to the previous article, we know how to build Active STS and Relying Party application (Figure 2 steps 1-3). Now, we’ll try to accomplish the scenario, which is presented in the following diagram (Figure2 steps 4-6).
Figure 2. WCF Service with STS
- The client sends a request message to the service (via application). The request message contains received token.
- The service validates the security token and processes the request. To validate a token connection between service and STS is not necessary – issuer validation is based on PKI (this mechanism will be further described in another article)
- (Optional) The service initializes and sends a response message to the client.
At first, we build and host WCF (with WS2007FederationHttpBinding) service projects (in this article, we won’t focus on implementation of WCF services, we assume that we know how to build and run sample WCF service with httpsBinding
). We prepare sample WCF services (SampleServiceOne
and SampleServiceTwo
) that will be hosted on IIS. The Relying Party application (a WinForm application), which will be a WCF services client, will use a token received from STS to authenticate and authorize. Both services SampleServiceOne
and SampleServiceTwo
provide the same functionalities (return information about claim identity) and use tokens issued by “trusted” STS.
var claimsPrincipal = OperationContext.Current.ClaimsPrincipal;
var identity = claimsPrincipal.Identity as ClaimsIdentity;
Listing 1: Get information about claim identity in WCF
The SampleServiceOne
is based on AspNetCompatibilityRequirements to verify client permissions, the SampleServiceTwo
explicitly verifies client permissions. When AspNetCompatibility
mode is enabled in WCF services, we can use the PrincipalPermissionAttribute
(SampleServiceOne
uses this functionality) to verify client’s identity (authenticate and authorize).
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class SampleServiceOne : SampleService, ISampleServiceOne
{
public SampleServiceOne()
{
ServiceName = "Service One";
}
[PrincipalPermission(SecurityAction.Demand, Role = "User", Authenticated = true)]
public string ComputeResponse(string input)
{
return GenerateResponse(input);
}
[PrincipalPermission(SecurityAction.Demand, Role = "Admin", Authenticated = true)]
public string ComputeResponseAdmin(string input)
{
return GenerateResponse(input);
}
[PrincipalPermission(SecurityAction.Demand, Role = "SuperAdmin", Authenticated = true)]
public string ComputeResponseSuperAdmin(string input)
{
return GenerateResponse(input);
}
}
Listing 2: SampleServiceOne implementation
The SampleServiceTwo
explicitly verifies user credentials (authenticate and authorize users).
public class SampleServiceTwo : SampleService, ISampleServiceTwo
{
public SampleServiceTwo()
{
ServiceName = "Service Two";
}
public string ComputeResponse(string input)
{
VerifyUserPermissions("User");
return GenerateResponse(input);
}
public string ComputeResponseAdmin(string input)
{
VerifyUserPermissions("Admin");
return GenerateResponse(input);
}
public string ComputeResponseSuperAdmin(string input)
{
VerifyUserPermissions("SuperAdmin");
return GenerateResponse(input);
}
private void VerifyUserPermissions(string role)
{
var claimsPrincipal = OperationContext.Current.ClaimsPrincipal;
if (!claimsPrincipal.Identity.IsAuthenticated || !claimsPrincipal.IsInRole(role))
{
throw new FaultException("Access denied.");
}
}
}
Listing 3: SampleServiceTwo implementation
To run WCF services with WS2007FederationHttpBinding
, we have to prepare service configuration. The configuration may look like “in Listing 4 and Listing 5” (all configurations of technical aspects connected with security will be described in the next post).
<ws2007federationhttpbinding>
<binding name="">
<security mode="TransportWithMessageCredential">
<message algorithmsuite="Default"
establishsecuritycontext="false" issuedkeytype="BearerKey">
</message></security>
</binding>
<binding name="WS2007FederationHttpBinding_ISampleServiceTwo">
<security mode="TransportWithMessageCredential">
<message establishsecuritycontext="false" issuedkeytype="BearerKey">
<tokenrequestparameters>
<trust:secondaryparameters
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:keytype xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:keytype>
<trust:canonicalizationalgorithm
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://www.w3.org/2001/10/xml-exc-c14n#</trust:canonicalizationalgorithm>
<trust:encryptionalgorithm
xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:encryptionalgorithm>
</trust:secondaryparameters>
</tokenrequestparameters>
</message>
</security>
</binding>
</ws2007federationhttpbinding>
Listing 4: Sample binding configuration
<behavior>
<servicemetadata httpgetenabled="true">
<servicedebug includeexceptiondetailinfaults="true">
<serviceauthorization principalpermissionmode="Always">
<servicecredentials useidentityconfiguration="true">
<clientcertificate>
<authentication certificatevalidationmode="None" revocationmode="NoCheck">
</authentication></clientcertificate>
</servicecredentials>
</serviceauthorization></servicedebug></servicemetadata></behavior>
Listing 5: Sample behaviour configuration
STS - Relying Party Application – WCF Communication
A Relying Party is an application or service that relies on claims for authentication. In our example, RP application is a simple Win Form application. The application sends an issue request to STS and receives Security Token, which is used to authenticate and authorize a user. The issued token is also used to authenticate and authorize client in WCF services. To run WCF method (with WS2007FederationHttpBinding
), first, we have to open communication channel using security token. In our example, we’ve created a sample service factory, which will create proxy to WCF service.
public class ServiceApiFactory : IDisposable
{
private readonly List<icommunicationobject> _activeServices;
private readonly SecurityToken _authToken;
public ServiceApiFactory(SecurityToken token)
{
_activeServices = new List<icommunicationobject>();
_authToken = token;
}
public void Dispose()
{
foreach (var service in _activeServices)
{
try
{
service.Close();
}
catch (CommunicationObjectFaultedException)
{
service.Abort();
}
catch (TimeoutException)
{
service.Abort();
}
}
}
public T GetService<t>(string endpointConfigurationName)
{
var factory = new ChannelFactory<t>(endpointConfigurationName);
_activeServices.Add(factory);
return factory.CreateChannelWithIssuedToken(_authToken);
}
}
Listing 6: Sample service factory implementation
The ServiceApiFactory
requires issued SecurityToken
; then it returns proxy to WCF service (with specified WCF service endpoint configuration).
using (var serviceApi = new ServiceApiFactory(_authController.GeToken()))
{
var client = serviceApi.GetService<isampleserviceone>("WS2007FederationHttpBinding_ISampleServiceOne");
}
Listing 7: Sample service factory usage
How to Run and Test a Sample Solution
To run the sample STS-RP-WCF implementation, we should execute the following steps:
- Get sample source code from Git repository (source code)
- Build STS.sln solution
- Host
SampleServiceOne
and SampleServiceTwo
project on IIS (use https) - Run Relying Party Application
- Login to STS using a user’s name/password credential (the current STS uses authentication mechanism, which verifies if user’s name corresponds to password, e.g., user’s name: user, password: user. If a user’s name is
Admin
, user is assigned to the User
and Admin
roles; if a user’s name is SuperAdmin
, user is assigned to the User
, Admin
and SuperAdmin
roles.
- As a user in the role of
User
or Admin
, “Call Service 1” and “Call Service 2”:
Figure 3. ServiceOne Call - Admin role
Figure 4. ServiceTwo Call - Admin role
- “Call Service 1” (and “Call Service 2”) runs (sequentially) three methods:
ComputeResponse
– requires client in User
’s role ComputeResponseAdmin
- requires client in Admin
’s role ComputeResponseSuperAdmin
- requires client in SuperAdmin
’s role
- Analyse execution results (the following figures show sample execution results)
- To verify that security token is issued by trusted STS, remove or comment Issuer thumbprint from
SampleServiceTwo
(or SampleServiceOne
) configuration file and make call to service once again.
<trustedissuers>
</add></trustedissuers>
Listing 8. Commented issuer thumbprint for local STS
Figure 5. ServiceTwo Call - untrusted issuer
Summary
This article explored the technical approach to authentication and authorization process based on claims in WCF services via STS. We have implemented working exemplary solution, which demonstrates how integration between WCF and WIF works. The next article will describe security aspects of authentication and authorization mechanism based on claims. We’ll try to explain Public Key Infrastructure roles in WIF.
Related Posts
- Introduction to Claims-Based Authentication and Authorization in .NET – how to build Active STS
- Introduction to Claims-Based Authentication and Authorization in .NET