2. The idea behind the scenario is very simple. The ADFSv2 instance can be a trusted issuer for your ACS Service Namespace, much like the issuer we defined in task 4 of the former exercise: the only difference is that it will issue tokens in SAML format instead of SWT. A client will request ACS tokens by sending one of such SAML tokens: the claim content of the SAML token is what the ACS will use for determining the content of the token it will issue to the requestor. From now on, it will be business as usual: the service will receive an SWT token, precisely as in shown in the first exercise, and will use it for determining access.
3. In this exercise you will learn how to modify a client in order to obtain a SAML token from an ADFSv2 instance and use it for requesting a token from ACS. You will also see how you can leverage the ADFSv2 metadata documents for automating part of the settings that the management service needs for configuring access. Finally, you will see how claims allow you to leverage user attributes such as group memberships for creating sophisticated access logic to your REST web service.Figure 25<br />A summary of the scenario enabled by this exercise. The client requests (1) and obtains (2) a SAML token from the ADFSv2 instance; it uses the same SAML token for requesting a token from ACS (3) and obtains a SWT token in return (4). The client then uses the SWT to invoke the service (5) and, upon successful authorization in ACSAuthorizationManager (6), reaches the intended service method.<br />Task 1 - Configure the ACS service to accept users from a directory<br />In this task we are going to build up on the ACS service we have built in exercise 1.<br />We already have a service namespace and a token policy that our service is configured to trust: what we need to do is define a new issuer, which will represent the ADFSv2 authority, and create the appropriate rules that will process the incoming SAML token and produce access decisions. <br />The exercise will modify an existing solution, which already contains a WCF service and its client ready for you to try. Open Microsoft Visual Studio 2008 with administrator privileges. From Start | All Programs | Microsoft Visual Studio 2008, right-click on Microsoft Visual Studio 2008 and select Run as administrator. <br />Open the ACSWithSAML.sln solution file located in the %YourInstallationFolder%absntroAccessControlServiceourcex02-UsingACSWithSAMLTokensegin folder.<br />In Solution Explorer, Service project, double click on the Program.cs file. Update the ServiceNamespace value with the service namespace you chose in the first exercise, task 2, step 4. <br />C#<br />private const string ServiceNamespace = quot;
{insert service namespace here}quot;
;<br />We'll now need to update our service to recognize tokens issued according to the token policy we defined on the first exercise. To do this, first get the token policy key from ACS using the following command in a Powershell console (navigate to %YourInstallationFolder%absntroAccessControlServiceourcessets). Once the command finishes execution, select the key from the console and perform a right-click (this will put the highlighted text in the clipboard). <br />Powershell<br />.cm.exe getall tokenpolicy<br />Figure 26<br />Get the token policy key generated by ACS<br />Paste the token policy key you just copied in the clipboard into the TokenPolicyKey constant on Servicerogram.cs file.<br />C#<br />private const string TokenPolicyKey = quot;
{insert token policy key here}quot;
;<br />Run the local STS that will simulate an ADFSv2. To do this, open a command prompt as administrator on %YourInstallationFolder%absntroToAccessControlServiceourcex02-UsingACSWithSAMLTokensssets and type LocalSTS.exe and keep it open for the rest of the exercise.<br />Figure 27<br />Running LocalSTS tool<br />Note: ADFSv2 is a server product with specific infrastructure requirements, among which there is Active Directory. Rather than forcing you to download, configure and manage a large virtual machine file, in this hands-on lab we will simulate an ADFSv2 instance with a custom STS written using Windows Identity Foundation. From the developer perspective the experience is absolutely equivalent: the instructions we give here would apply without any modification if the STS would be exposed by an ADFSv2 instance.<br />Now you will configure our STS as a trusted issuer on ACS. ACS is able to automate a large part of the operation, simply by taking advantage of the metadata exposed by the STS itself. In this lab we provide a tool, FedMetadataClient, which will help you to send to the management service the opportune settings. Similarly to what you have done for the ACM tool in exercise 1, you need to configure the FedMetadataClient tool by opening the FedMetadataClient.exe.config file (from LabsntroToAccessControlServiceourcex02-UsingACSWithSAMLTokensssets) and assigning the right values to the management key and service name. You got those two values on Task 2 of the first exercise, on step 4 (when you chose the Service Namespace).<br />XML<br /><?xml version=quot;
1.0quot;
encoding=quot;
utf-8quot;
?><br /><configuration><br /> <appSettings><br /> <add key=quot;
stsBaseAddressquot;
value=quot;
localhost/localstsquot;
/><br /> <add key=quot;
stspathquot;
value=quot;
Trust/13/UserNamequot;
/><br /> <add key=quot;
serviceNamespacequot;
value=quot;
{insert service namespace here}quot;
/><br /> <add key=quot;
acsHostNamequot;
value=quot;
accesscontrol.windows.netquot;
/><br /> <add key=quot;
applies_toquot;
value=quot;
http://localhost/weatherforecastquot;
/><br /> <add key=quot;
mgmtKeyquot;
value=quot;
{insert management key here}quot;
/><br /> </appSettings><br /></configuration><br />Run the FedMetadataClient.exe tool. To do this, open command prompt on %YourInstallationFolder%absntroToAccessControlServiceourcex02-UsingACSWithSAMLTokensssets and type FedMetadataClient.exe<br />Figure 28<br />Running FedMetadataClient from command line<br />The FedMetadataClient tool retrieves all the relevant parameters from the STS and uses them against the management service to create an issuer. Let’s run the ACM tool to get the list of all issuers and verify that the new issuer has been correctly created. To do this, open a Powershell and run the following command.<br />Powershell<br />.cm.exe getall issuer<br />Figure 29<br />Get the issuer ID for the SAML issuer just created<br />Now that you created a new issuer, you need to retrieve its Id so that you can reference it when you will create the new access rules. Look for the serviceNamespaceSAML issuer, and copy the id: iss_XXXXXX attribute. To do this, select the id using the mouse and right click to place the content on the clipboard. Paste it on the LabsntroToAccessControlServiceourcex02-UsingACSWithSAMLTokenseginetup.ps.txt file on the %adfsissuer% placeholder.<br />You already defined a scope for your service: since you want to create a new rule in that scope, you need to retrieve the scope id in order to reference it. Run the ACM tool to get the scopes and lookup the scope for the weatherforecast service. To do this, open a Powershell and run the following command.<br />Powershell<br />.cm.exe getall scope<br />Figure 30<br />Get the scope id for the weatherforecast<br />Look for the weatherforecast scope. Copy the id: scp_XXXXXX attribute. To do this, select the id using the mouse and right click to place the content on the clipboard. Paste it on the Setup.ps.txt file on the %scopeid% placeholder.<br />Your new access control rule will be based on the content of the SAML token coming from the ADFSv2 instance of your trusted partner. Let’s say that you know that employees in the security group “Pilots” are meant to have access to the getforecast3days method: all you need to do is creating a rule that issues an action claim with value “Get3DaysForecast” whenever an incoming claim of type http://schemas.xmlsoap.org/claims/Group and value “Pilots” is received from this issuer. Paste in powershell the command from the setup file.<br />Powershell<br />.cm.exe create rule -scopeid:%scopeid% -inclaimissuerid:%adfsissuer% -inclaimtype:http://schemas.xmlsoap.org/claims/Group -inclaimvalue:Pilots -outclaimtype:action -outclaimvalue:Get3DaysForecast -name:pilotsgroup3days<br />Figure 31<br />Creating a rule to allow calling Get3DaysForecast<br />This is all you need to do for configuring your ACS Service Namespace. Next, we will explore the changes that the client must introduce for successfully obtaining a SWT token from ACS when presenting a SAML token: once that happens, it is business as usual for everything else.<br />Task 2 - Create an “ADFSv2 ready” client<br />In this task you will add to the client the code that retrieves a SAML token from the local STS, send it to ACS, get a SWT token back and finally call the service transmitting the SWT token in an HTTP header.<br />In Solution Explorer, right click on the Client project and select Add Reference. Select the Microsoft.IdentityModel assembly and click OK. This will add the required assembly reference to use Windows Identity Foundation classes.<br />Figure 32<br />Adding a reference to Microsoft.IdentityModel<br />In Solution Explorer, Client project, double click on the Program.cs file. Add the following using directives at the beginning of the file for the code we'll be adding later. <br />(Code Snippet – Introduction to ACS Lab - Ex02 Client Usings)<br />C#<br />namespace Client<br />{<br /> using System;<br /> using System.Collections.Specialized;<br /> using System.IdentityModel.Tokens;<br /> using System.Linq;<br /> using System.Net;<br /> using System.ServiceModel;<br /> using System.ServiceModel.Security;<br /> using System.ServiceModel.Web;<br /> using System.Text;<br /> using System.Web;<br /> using Microsoft.IdentityModel.Protocols.WSTrust;<br /> using Microsoft.IdentityModel.Protocols.WSTrust.Bindings;<br />The last two namespaces are from Windows Identity Foundation: we will use the classes found there for retrieving the SAML token from the local STS.<br />Add the following constants in the body of the Program class.<br />(Code Snippet – Introduction to ACS Lab - Ex02 Client constants)<br />C#<br />public class Program<br />{<br /> private const string ServiceNamespace = quot;
{insert service namespace here}quot;
;<br /> private const string AcsHostName = quot;
accesscontrol.windows.netquot;
;<br /> private const string StsBaseAddress = quot;
localhost/localstsquot;
;<br /> private const string StsPath = quot;
Trust/13/UserNamequot;
;<br /> public static void Main(string[] args)<br />Update the Service Namespace (the one you entered in Task 2 of the first exercise, step 4) used in the client Clientrogram.cs file. To do this, replace the ServiceNamespace constant in the code. <br />C#<br />private const string ServiceNamespace = quot;
{insert service namespace here}quot;
;<br />Add the following lines of code to call the local STS and receive a SAML token in return. The SAML token will then be sent to ACS to be exchanged with a SWT token. <br />Note: The order of these instructions aim at helping you understand what it takes for a client to be able to use ACS, hence it follows a top-down approach. The code won’t compile at this point, but it eventually will, once you will have followed the instructions in the next 3 steps<br />(Code Snippet – Introduction to ACS Lab - Ex02 Client call STS)<br />C#<br />public static void Main(string[] args)<br />{<br /> string stsAddress = string.Format(quot;
https://{0}/{1}quot;
, StsBaseAddress, StsPath);<br /> string acsSTSAddress = string.Format(quot;
https://{0}.{1}/WRAPv0.8quot;
, ServiceNamespace, AcsHostName);<br /> string samlAssertion = GetSamlAssertion(stsAddress, acsSTSAddress);<br /> string acsToken = GetACSToken(samlAssertion);<br />Add the definition of the GetSamlAssertion method, which gets a token from the local STS. To do that, copy the following code at the end of the Program class.<br />(Code Snippet – Introduction to ACS Lab - Ex02 GetSamlAssertion Method)<br />C#<br />...<br />public static void Main(string[] args)<br />{<br /> ...<br />}<br />private static string GetSamlAssertion(string stsAddress, string acsStsAddress)<br />{<br /> WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(<br /> new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential),<br /> new EndpointAddress(new Uri(stsAddress)));<br /> trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;<br /> RequestSecurityToken rst = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue, WSTrust13Constants.KeyTypes.Bearer);<br /> rst.AppliesTo = new EndpointAddress(acsStsAddress);<br /> rst.TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml2TokenProfile11;<br /> WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel();<br /> GenericXmlSecurityToken token = channel.Issue(rst) as GenericXmlSecurityToken;<br /> return token.TokenXml.OuterXml;<br />}<br />The code here takes advantage of the object model for Windows Identity Foundation, and specifically of the WSTrustChannel class which makes it easy to send issuing requests to a WS-Trust STS.<br />The code in step 5 makes use of the GetACSToken method, which gets a token from ACS based on the SAML token. Add the definition of GetACSToken by coping the following code at the end of Program class. <br />(Code Snippet – Introduction to ACS Lab - Ex02 GetACSToken Method)<br />C#<br />public class Program<br />{<br /> ...<br />private static string GetSamlAssertion(string stsAddress, string acsStsAddress)<br /> ...<br /> private static string GetACSToken(string samlAssertion)<br /> {<br /> WebClient tokenClient = new WebClient();<br /> tokenClient.BaseAddress = string.Format(quot;
https://{0}.{1}quot;
, ServiceNamespace, AcsHostName);<br /> NameValueCollection values = new NameValueCollection();<br /> values.Add(quot;
wrap_SAMLquot;
, samlAssertion);<br /> values.Add(quot;
applies_toquot;
, quot;
http://localhost/weatherforecastquot;
);<br /> byte[] responseBytes = tokenClient.UploadValues(quot;
WRAPv0.8quot;
, values);<br /> string response = Encoding.UTF8.GetString(responseBytes);<br /> return response<br /> .Split('&')<br /> .Single(value => value.StartsWith(quot;
wrap_token=quot;
, StringComparison.OrdinalIgnoreCase))<br /> .Split('=')[1];<br /> }<br />}<br />You can see how the method body here closely resembles the code we used in exercise 1 for performing a similar function with a symmetric key.<br />Add the code that will add the ACS token in the authorization HTTP header. To do that, add the following code right before calling the service.<br />(Code Snippet – Introduction to ACS Lab - Ex02 WRAP Header)<br />C#<br />using (new OperationContextScope(proxy as IContextChannel))<br />{<br /> string authHeaderValue = quot;
WRAPv0.8quot;
+ quot;
quot;
+ HttpUtility.UrlDecode(acsToken);<br /> WebOperationContext.Current.OutgoingRequest.Headers.Add(quot;
authorizationquot;
, authHeaderValue);<br /> // call the service and get a response<br /> try<br /> {<br />...<br />Exercise 2: Verification<br />In order to verify that you have correctly performed all steps in exercise two, proceed as follows:<br />Right click on the Service project (in Solution Explorer), and select Debug | Start new instance to run the Service.<br />Figure 33<br />Service console<br />Right click on the Client project (in Solution Explorer), and select Debug | Start new instance to run the Client.<br />Figure 34<br />Client console showing the 3 days forecast but not the 10 days forecast because the user doesn’t have access to that.<br />Verify that the 3 days forecast is retrieved by looking at the console output. You'll also notice that the console displays an error on the following line. This is exactly in line with expectations: our rule granted this client access only to the Get3DaysForecast method , hence the attempt to access Get10DaysForecast was blocked with a (401) Unauthorized return code. This happened because the STS generated a SAML token with a group claim with value “Pilots” and we created an ACS rule that transform the group claim “Pilots” to Get3DaysForecast.<br />Note: as an optional exercise, you can try to create a second rule that would grant access to the Get10DaysForecast action for the “Pilots” group. Hint: you can follow the same procedure we illustrated in the verification section of exercise 1.<br />Exercise 2: Summary<br />In this exercise you have learned how to take advantage of ADFSv2 identities for managing access control to REST services. What made the scenario possible is the ability of the Access Control Service of processing SAML tokens issued by ADFSv2, transforming the claims from the incoming SAML assertion in authorization directives in the resulting SWT token.<br />Exercise 2 used the same service you developed in exercise 1: however the entire exercise 2 was completed without touching the code of the service. The service was already configured to trust SWT tokens issued by ACS, hence all it was needed for enabling a new service consumer was few calls to the ACS management service.<br />Summary<br />By completing this Hands-On Lab you have learned how to:<br />Modify your WCF services to take advantage of ACS for handling access control<br />Create and manage ACS Service Namespaces; work with token policies, issuers, scopes and rules<br />Invoke REST web services secured by ACS<br />Obtain tokens from ACS via SAML token, and use them to invoke REST web services<br />You can easily generalize what you have learned here to different scenarios or technologies: since all you need is an HTTP-capable client, it is easy to imagine how to apply the steps you have seen in this lab for requesting tokens from the widest range of platforms, devices and programming styles. As you have seen in the two exercises, once your REST services are configured to trust ACS it does not really matter which technology or credentials your clients will use: your services are decoupled from those changes.<br />When advanced capabilities are available, ACS is ready to take advantage of them: you can use what you learned in exercise 2 for taking advantage of your investment in Active Directory and ADFSv2 for extending to the REST world the sophisticated claims-based access control policies that until now were available only to WS-* stacks.<br />We hope that the lab inspired you to think about how the ACS can help you solve your access control challenges, and we invite you to experiment with the SDK and all the rest of the learning material Microsoft offers on this topic.<br />