{"id":415,"date":"2009-03-17T04:08:00","date_gmt":"2009-03-17T13:08:00","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/2009\/03\/17\/a-visual-tour-of-the-net-access-control-service-part-2-fun-with-scopes-and-issuers\/"},"modified":"2009-03-17T04:08:00","modified_gmt":"2009-03-17T13:08:00","slug":"a-visual-tour-of-the-net-access-control-service-part-2-fun-with-scopes-and-issuers","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2009\/03\/17\/a-visual-tour-of-the-net-access-control-service-part-2-fun-with-scopes-and-issuers\/","title":{"rendered":"A visual tour of the .NET Access Control service, part 2: fun with scopes and issuers"},"content":{"rendered":"<div class=\"wlWriterHeaderFooter\" style=\"float:right;margin:0px;padding:0px 0px 4px 8px\">digg_url = &#8220;http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/03\/17\/a-visual-tour-of-the-net-access-control-service-part-2-fun-with-scopes-and-issuers.aspx&#8221;;digg_title = &#8220;A visual tour of the .NET Access Control service, part 2: fun with scopes and issuers&#8221;;digg_bgcolor = &#8220;#FFFFFF&#8221;;digg_skin = &#8220;normal&#8221;;digg_url = undefined;digg_title = undefined;digg_bgcolor = undefined;digg_skin = undefined;<\/div>\n<p>Here we are again. I am just back from <a href=\"http:\/\/www.microsoft.com\/belux\/techdays\/about.aspx\">Belgium\u2019s TechDays<\/a>, and I can still savor the nice feeling you get from talking in front of a very interested audience \ud83d\ude42 I\u2019m really glad to see that <a href=\"http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/03\/04\/identity-techdays-in-belgium-10-12-march-2009.aspx\">both the cloud and claims based identity<\/a> are enjoying the attention they deserve! I have been asked to share the samples I have shown in my two sessions: sharing the end to end demo I have shown for Geneva will require some time &amp; creativity, but I can certainly give more details about one of the ACS demo. In fact, that\u2019s the perfect excuse for writing the promised follow-up to the <a href=\"http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/01\/08\/a-visual-tour-of-the-net-access-control-service-via-azure-services-management-console.aspx\">Visual Tour of the ACS<\/a> post.<\/p>\n<h1>Recap<\/h1>\n<p>In the <a href=\"http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/01\/08\/a-visual-tour-of-the-net-access-control-service-via-azure-services-management-console.aspx\">last installment<\/a> we took a good look at the structure of an ACS solution, by examining the Echo sample from the SDK with the <a href=\"http:\/\/code.msdn.microsoft.com\/AzureManagementTools\">Azure Services Management Console<\/a>. <\/p>\n<p>We briefly went through the steps of solution provisioning and solution credentials management; then we examined the list of STSes we get for every solution, focusing on the one dedicated to the ServiceBus. We listed the various elements we can use for defining our access logic: scopes, claim types, issuers, certificates\u2026 and above all, rules. We examined the default rules that are available in the default ServiceBus scope, and observed their behavior while running the Echo sample. It\u2019s now time to snap out of this look-don\u2019t-touch spell and mess with some settings!<\/p>\n<h1>The \u201cVote for Hardware\u201d Scenario<\/h1>\n<p>Let\u2019s say that your business is leasing hardware to business customers and providing all-inclusive maintenance. For example: Contoso equips its workforce with laptops and phones leased from you. When something breaks, you take care of fixing or substituting it. When the lease expires, let\u2019s say every 2 years, you get back your hardware: Contoso then starts a new leasing with new hardware hardware equipment, and the cycle goes on until Contoso is happy with your services.<\/p>\n<p>The end of a lease cycle is approaching, and you are planning your hardware refresh not just for Contoso, but for many different business customers. You observed that the more the workforce is satisfied with the laptop and phone models you provide, the less they tend to call your cost center: hence you\u2019d like to poll the workforce of your various customers for making sure that you meet their preferences. That\u2019s not an easy task: you need to poll a very heterogeneous population, partitioned through multiple identity providers, in different connectivity conditions, perhaps behind firewalls whitelisting the list of websites a browser can visit, and so on and so on. Luckily you can count on the .NET Services \ud83d\ude42 the outline of the solution is as follows:<\/p>\n<ul>\n<li>You create two ServiceBus services, VoteForPhone and VoteForLaptop. Those two services are hosted on your premises and will take care of gathering the preferences for phone and laptop models, respectively<\/li>\n<li>You configure your .NET solution for trusting the IPs of all your customers<\/li>\n<li>You distribute the client, so that every customer can invoke your services while authenticating by using its own identity provider<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_422caa9e-f778-4e00-a9cf-fd197cb4182e.png\" width=\"504\" height=\"287\" \/> <\/p>\n<h1>The Services &amp; the Client<\/h1>\n<p>Of course this is a demo, designed for making a point from stage; hence it contains various naiveties that you are not advised to repeat in production. Also, my purpose here is not teaching how to use WCF for writing good services: in fact, since we are interested in the access control part, any couple of ServiceBus services exposed through the same .NET solution will do. You can copy the echo sample in a new directory, slightly change its address, then run the original and the modified version at the same time: to all practical means, that\u2019s all you\u2019d need for reproducing what I am going to demonstrate here.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_c51039dd-7f75-4542-8da2-a076d07b057f.png\" width=\"276\" height=\"313\" \/> <\/p>\n<p>Just for giving you the backstage view, however, in my case I created a ServiceContract that accepts an int as a vote; I have a servicehost that creates two separate instances of the contract, one for the phone voting service and one for the laptop voting service; both services communicate the preferences they receive via delegate, to a WPF app which constantly shows the current results of the tally as it unfolds. As anticipated, this is an application for the stage \ud83d\ude42 pseudocode below:<\/p>\n<div>\n<pre><span style=\"color: #0000ff\">using<\/span> System;\r\n<span style=\"color: #0000ff\">using<\/span> System.ServiceModel;\r\n<span style=\"color: #0000ff\">using<\/span> Microsoft.ServiceBus;\r\n\r\n<span style=\"color: #0000ff\">namespace<\/span> WpfVotingApp\r\n{\r\n\r\n    [ServiceContract]\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">interface<\/span> ISingleVoter\r\n    {\r\n        [OperationContract]\r\n        <span style=\"color: #0000ff\">void<\/span> Vote(<span style=\"color: #0000ff\">int<\/span> a);\r\n    }\r\n\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">interface<\/span> SingleVoterChannel : ISingleVoter, IClientChannel { }\r\n\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">interface<\/span> IDisplayVote\r\n    {\r\n        <font color=\"#0000ff\">\/\/..<span style=\"color: #0000ff\"><\/span><\/font>\r\n    }\r\n\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">delegate<\/span> <span style=\"color: #0000ff\">void<\/span> VoteDelegate(<span style=\"color: #0000ff\">int<\/span> a);\r\n\r\n    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = <span style=\"color: #0000ff\">true<\/span>)]\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">class<\/span> SingleVoterService : ISingleVoter\r\n    {\r\n        VoteDelegate delVote;\r\n        <span style=\"color: #0000ff\">public<\/span> SingleVoterService(VoteDelegate vd)\r\n        {\r\n            <span style=\"color: #0000ff\">this<\/span>.delVote = vd;\r\n        }\r\n\r\n        <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">void<\/span> Vote(<span style=\"color: #0000ff\">int<\/span> a)\r\n        {\r\n            delVote(a);\r\n        }\r\n    }\r\n\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">class<\/span> VoterPhone : SingleVoterService\r\n    {\r\n        <span style=\"color: #0000ff\">public<\/span> VoterPhone(VoteDelegate vd):<span style=\"color: #0000ff\">base<\/span>(vd){}\r\n    };\r\n    <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">class<\/span> VoterLaptop : SingleVoterService\r\n    {\r\n        <span style=\"color: #0000ff\">public<\/span> VoterLaptop(VoteDelegate vd) : <span style=\"color: #0000ff\">base<\/span>(vd) { }\r\n    };\r\n\r\n    \r\n\r\n    <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">class<\/span> MyDoubleServiceHost\r\n    {\r\n        <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">static<\/span> ServiceHost myServiceHost1 = <span style=\"color: #0000ff\">null<\/span>;\r\n        <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">static<\/span> ServiceHost myServiceHost2 = <span style=\"color: #0000ff\">null<\/span>;\r\n\r\n        <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> StartService1(VoterPhone instance)\r\n        {\r\n            <span style=\"color: #008000\">\/\/..<\/span>\r\n        }\r\n\r\n        <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> StartService2(VoterLaptop instance)\r\n        {\r\n            <span style=\"color: #008000\">\/\/..        <\/span>\r\n        }\r\n\r\n        <span style=\"color: #0000ff\">internal<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> StopService()\r\n        {\r\n            <span style=\"color: #008000\">\/\/Call StopService from your shutdown logic<\/span>\r\n            <span style=\"color: #008000\">\/\/...<\/span>\r\n        }\r\n    }\r\n    \r\n}<\/pre>\n<\/div>\n<p>From my WPF app (WpfVotingApp) I simply start the two services (both published on the ServiceBus using the solution password) and I pass on the delegate that updates the UI.<\/p>\n<p>The client is very simple: in fact, it\u2019s just a console app which allows you to authenticate with the service bus by using a managed card and cast your votes. This is very, very similar to what we do in the ACS hands on lab in <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=130354\">the training kit<\/a>. Below there\u2019s a code fragment that hints at how the client works:<\/p>\n<div>\n<pre><span style=\"color: #0000ff\">namespace<\/span> ConsoleVotingClient\r\n{\r\n    <span style=\"color: #0000ff\">class<\/span> Program\r\n    {\r\n        <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> Main(<span style=\"color: #0000ff\">string<\/span>[] args)\r\n        {\r\n            TransportClientEndpointBehavior behavior = <span style=\"color: #0000ff\">null<\/span>;\r\n\r\n            Console.WriteLine(<span style=\"color: #006080\">&quot;Enter a number to vote for a phone (or [Enter] to skip):&quot;<\/span>);\r\n            Console.WriteLine(<span style=\"color: #006080\">&quot;[1]XPERIA [2]TOUCH [3]OMNIA&quot;<\/span>);\r\n                 \r\n            <span style=\"color: #0000ff\">string<\/span> input = Console.ReadLine();\r\n\r\n            <span style=\"color: #0000ff\">try<\/span>\r\n            {\r\n\r\n                behavior = <span style=\"color: #0000ff\">new<\/span> TransportClientEndpointBehavior();\r\n                behavior.CredentialType = TransportClientCredentialType.FederationViaCardSpace;\r\n                behavior.Credentials.FederationViaCardSpace.ClaimTypeRequirements.Add(<span style=\"color: #0000ff\">new<\/span> ClaimTypeRequirement(<span style=\"color: #006080\">&quot;http:\/\/ipsts.federatedidentity.net\/group&quot;<\/span>));\r\n\r\n                VoteForPhone(behavior, input);\r\n\r\n            }\r\n<span style=\"color: #008000\">\/\/..<\/span>\r\n       <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> VoteForPhone(TransportClientEndpointBehavior bev, <span style=\"color: #0000ff\">string<\/span> inp)\r\n       {\r\n           Uri serviceUri = <span style=\"color: #0000ff\">new<\/span> Uri(String.Format(<span style=\"color: #006080\">&quot;sb:\/\/{0}\/services\/{1}\/VoterPhone\/&quot;<\/span>, ServiceBusEnvironment.DefaultRelayHostName, ConfigurationSettings.AppSettings[<span style=\"color: #006080\">&quot;userURIfragment&quot;<\/span>]));\r\n\r\n\r\n           ChannelFactory&lt;SingleVoterChannel&gt; channelFactory = <span style=\"color: #0000ff\">new<\/span> ChannelFactory&lt;SingleVoterChannel&gt;(<span style=\"color: #006080\">&quot;PhoneRelayEndpoint&quot;<\/span>, <span style=\"color: #0000ff\">new<\/span> EndpointAddress(serviceUri));\r\n           channelFactory.Endpoint.Behaviors.Add(bev);\r\n\r\n           SingleVoterChannel v = channelFactory.CreateChannel();\r\n           v.Open();\r\n\r\n           <span style=\"color: #0000ff\">if<\/span> (inp != <span style=\"color: #0000ff\">string<\/span>.Empty)\r\n           {\r\n               v.Vote(<span style=\"color: #0000ff\">int<\/span>.Parse(inp));\r\n               Console.WriteLine(<span style=\"color: #006080\">&quot;Your vote for a phone has been sent to the server.&quot;<\/span>);\r\n           }\r\n       }<\/pre>\n<\/div>\n<p>I am resisting the temptation to just post the code here, because I\u2019d really like to encourage you guys to write your own: it\u2019s not hard, and you learn much more by doing. Worst care, remember that you don;t need a fancy UI&quot;: again, 2 instances of the echo service with different URIs (but SAME SOLUTION) would work, too.<\/p>\n<h1>Enabling a trusted partner to invoke our services<\/h1>\n<p>Our objective is clear: we want to expose the services above to our customers. We don\u2019t have to worry about connectivity, thanks to the ServiceBus features: but we do need to explicitly grant access to the right user population. We\u2019ll do it for one federated partner, and you\u2019ll see that by extension it\u2019s not hard to repeat the same procedure for any additional partners. As in good tradition, we\u2019ve done this in past posts and <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=130354\">in the training kit<\/a>, we are going to use <a href=\"http:\/\/federatedidentity.net\/\">federatedidentity.net<\/a> as our mockup partner. In fact, here I assume that you went through Task 1 and the steps 7+ of the access control lab in the <a href=\"http:\/\/www.microsoft.com\/downloads\/details.aspx?FamilyID=413E88F8-5966-4A83-B309-53B7B77EDF78&amp;displaylang=en\">training kit<\/a>: those steps are necessary for creating your account on federatedidentity.net, obtaining a managed card and configuring the ACS as a valid token destination.<\/p>\n<p>Let\u2019s open our solution in <a href=\"http:\/\/code.msdn.microsoft.com\/AzureManagementTools\">the MMC<\/a> as explained in the <a href=\"http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/01\/08\/a-visual-tour-of-the-net-access-control-service-via-azure-services-management-console.aspx\">former installment<\/a> and see where we left it last time: navigate to the servicebus node and select its scope. You\u2019ll get a view similar to the following:<\/p>\n<p>&#160;<img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_6853f587-5628-4102-ab8d-75a2b3ebe8b4.png\" width=\"704\" height=\"416\" \/> <\/p>\n<p>If we want to accept identities coming from a partner, the first thing we have to do is\u2026 adding the partner in our list of trusted issuers. The red ellipse above shows the UI element we need to use for adding an issuer. We will get a dialog as the following:<\/p>\n<p>&#160;<img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_80f538c0-33a4-4204-bd1e-29f9d03695bf.png\" width=\"204\" height=\"193\" \/> <\/p>\n<p>Again, this is the same as task 2.1f in the ACS HOL in the training kit. Note that the cert you find in the kit may be expired by now: you can retrieve a new one by using <a href=\"http:\/\/www.leastprivilege.com\/DownloadingTheCertificateFromAnSSLSite.aspx\">the code from Dominick\u2019s blog<\/a> or <a href=\"http:\/\/blogs.msdn.com\/vbertocci\/archive\/2008\/03\/31\/using-federatedidentity-net-managed-cards-with-biztalk-services-sdk.aspx\">step 2 from this old post of mine<\/a>.<\/p>\n<p>Once you\u2019ll click OK, federatedidentity.net will appear in the list of issuers. Note that, since it\u2019s a user generated issuer (as opposed to system ones), the icon is of a different color.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_d6ae3b74-36ae-42c2-882f-51baf0693370.png\" width=\"604\" height=\"516\" \/> <\/p>\n<p>Veeery well, now we can work with tokens coming from federatedidentity.net (fedid.net from now on). Are we done yet? Recall what we learned last time: in order to be able to invoke a servicebus service, we need to get a token containing an output claim \u201cAction\u201d with value \u201cSend\u201d. Hence, we need to create a rule that transforms claims from fedid into the right Action claim. For the way in which we configured fedid.net, we know that we will get from it a claim \u201cGroup\u201d with value \u201cDomain Users\u201d. This claim type is not part of the default types, hence we need to add it. If we click on the \u201cAdd Claim Type\u201d link in the action pane on the right of the MMC, we\u2019ll get the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_990272ca-61e7-4624-b502-2712ec879564.png\" width=\"339\" height=\"263\" \/> <\/p>\n<p>Fill in the dialog with the values shown in the pic above, and hit OK: the claim types list will now include out custom type.<\/p>\n<\/p>\n<\/p>\n<\/p>\n<\/p>\n<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_c089f8f3-2d4b-4844-bae7-f98d979f48d1.png\" width=\"526\" height=\"223\" \/> <\/p>\n<p>Now we finally have all the elements for expressing our access cotnrol rule. Let\u2019s hit \u201cadd new rule\u201d on the action pane and fill the dialog as shown below:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_e21f9549-a00e-408c-9f16-9aa3d352830f.png\" width=\"504\" height=\"290\" \/> <\/p>\n<p>Easy: it reads \u201cif you receive a token from fedid.net containing a claim Group with value Domain Users, include in the output token the claim Action with value Send\u201d. The main view is updated accordingly:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_1eba2325-708c-4041-97f8-fc93d29dc4d0.png\" width=\"604\" height=\"329\" \/> <\/p>\n<\/p>\n<p>Finally we are ready to give our services a spin. Let\u2019s start the app that will host the services, and hit \u201cStart Services &gt;&gt;\u201d:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_85bad1e7-9d00-4a65-8222-f6f7710d6d23.png\" width=\"404\" height=\"440\" \/> <\/p>\n<p>Our app is now ready to accept calls. Remember, this app runs on your premises and accepts calls from everywhere. Let\u2019s start our client, which instead is supposed to run on the desktops of our customers:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_9db56fc2-bb55-4fe4-8476-e33192131109.png\" width=\"504\" height=\"257\" \/> <\/p>\n<p>Nice UI, eh? \ud83d\ude42 for our purposes, it should suffice. Let\u2019s vote for the Xperia by typing \u20181\u2019 and hitting enter.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_f0b4ec5e-ec34-4a07-961b-fa583b0b2fc6.png\" width=\"504\" height=\"409\" \/> <\/p>\n<p>As soon as we do so, the client attempts to acquire the token that will be needed for contacting the ACS:as a result, the cardspace prompt appears. The only suitable card is the one from fedid.net: let\u2019s select it and hit Preview, since we want to take a look at the token we\u2019ll get before forwarding it to the ACS.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_7e627cd6-edc3-4434-be02-df1ef2d4bad2.png\" width=\"454\" height=\"330\" \/> <\/p>\n<p>The token we are requesting indeed contains the claim Group; let\u2019s hit Retrieve.<\/p>\n<\/p>\n<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_78249481-8b8f-41f0-8707-4578e70d01e5.png\" width=\"454\" height=\"339\" \/> <\/p>\n<p>Yep, that\u2019s exactly the value we specified in the input clause of our rule: hence we are confident that it will work as expected. Let\u2019s hit Send.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_17ceb827-89e5-4fa2-85a4-cd9ce7980ae0.png\" width=\"504\" height=\"255\" \/> <\/p>\n<p>The phone vote has been sent to the server, and we are already prompted for our laptop vote. Let\u2019s see what happened to the voting app:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_63527305-51b9-4c96-ba52-1b64b28c6ac8.png\" width=\"404\" height=\"440\" \/> <\/p>\n<p>Sure enough, the application received and accepted our vote! That wasn\u2019t too hard to enable partner access, was it \ud83d\ude42<\/p>\n<p>Let\u2019s also vote for a laptop:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_d04c3c90-1ff7-4f03-96c0-475f5a8f7b52.png\" width=\"504\" height=\"255\" \/> <\/p>\n<p>and our vote is promptly recorded:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_7fce6b98-ecc9-4918-8f07-64bf85ec8972.png\" width=\"404\" height=\"440\" \/> <\/p>\n<p>Interestingly enough, we don\u2019t get prompted again for a token: that\u2019s because I am using the same TransportClientEndpointBehavior for both channels, hence the call to the second service uses the same token obtained in the call to the first.<\/p>\n<p>Ok, now that we accomplished our primary goal we can fool around a bit; let\u2019s play with scopes. Don\u2019t close the voting app just yet!<\/p>\n<h1>Fun with scopes<\/h1>\n<p>As mentioned elsewhere, scopes are a tool that you can use for manage your rules and for fine-tune the behavior of different endpoints. Since we are not in production, let\u2019s experiment a bit before explaining things further; for example, we can add a scope corresponding to our VoterLaptop service and see what happens.<\/p>\n<p>Adding a scope is easy: you point to the node of the STS you want to manage, in our case the ServiceBus one, right click and simply choose Add Scope:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_0a68e6f6-6227-41e7-8814-8142a3d1111a.png\" width=\"357\" height=\"189\" \/> <\/p>\n<p>fill in the right URI, and after a short server sync your tree will have a new scope node:<\/p>\n<p>&#160;<img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_430c4e1d-e403-42c9-83e2-34314f7aa63d.png\" width=\"450\" height=\"181\" \/> <\/p>\n<p>If you select the new node, you\u2019ll discover that by default it contains\u2026 nothing:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_24022469-db7f-490b-b0f0-ec0215095a44.png\" width=\"504\" height=\"424\" \/> <\/p>\n<p>Well, not exactly nothing: it does not have default rules, but it does contain our custom issuer and claim type.<\/p>\n<p>Let\u2019s re-launch our client and hit again on our running instance of the voting app. Our new vote for a phone works well:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_fe389e58-6267-436c-b598-506f887ae523.png\" width=\"504\" height=\"255\" \/> <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_5ab89c48-e474-4666-8075-3fa590bd9db5.png\" width=\"404\" height=\"440\" \/> <\/p>\n<p>Our attempt to vote for a laptop, however, is not as lucky:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_70d66b26-b672-4d99-8824-ec3516447d48.png\" width=\"504\" height=\"255\" \/> <\/p>\n<p>We get an error: the servicebus complains that we didn\u2019t have the necessary Action claim. Really? How come? If you think about it for a moment, it makes perfect sense. When we called the VoterPhone service, the scope that gave the best match was the root one (<a href=\"http:\/\/services.windows.net\/services\/VibroVoter3\">http:\/\/services.windows.net\/services\/VibroVoter3<\/a>); that scope does contain a rule that enables us to call the service with a fedid.net token. When we call VoterLaptop, however, the scope which gives the best match is is indeed our newly created scope <a href=\"http:\/\/services.windows.net\/services\/VibroVoter3\/VoterLaptop\">http:\/\/services.windows.net\/services\/VibroVoter3\/VoterLaptop<\/a>; and that scope does not contain any rule, hence no Action claims for you!<\/p>\n<p>The solution is pretty simple: we just create the suitable rule in the scope, following the same procedure as before.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_0ece317b-6bee-47e1-b560-1b6ea96acb40.png\" width=\"504\" height=\"424\" \/> <\/p>\n<p>Note: here we are setting up the same rule for simplicity, since we have just one user for this scenario, however notice how I could use this for achieving finer grained control. For example I may use this scope for imposing that VoterLaptop can be called only by users presenting in input a claim Group with value Managers instead of Domain Users, while every other service would still match the top scope. Nice \ud83d\ude42<\/p>\n<p>Just for showing you that it works, let\u2019s go through another round of votes:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_c1fb1492-9a16-4dd4-aa66-39a53b55d690.png\" width=\"604\" height=\"373\" \/> <\/p>\n<p>This time, everything worked as expected.<\/p>\n<p>Now, I am sure that some of you are on the verge of erupting with \u201cWait a minute! Why did you have to re-create the Send rule in the new scope, but you didn\u2019t have to do the same with the Listen rule?\u201d. Good point, good point. The fact is that <em>for the entire duration of our walkthrough I have never closed the WPF voting application<\/em>. The presence of the Listen claim is verified at the time in which one service is attempting to publish itself on the ServiceBus, and at the time of publication our service had the necessary claim available. Let\u2019s put this theory to test. Let\u2019s shut down the WPF application, and let\u2019s restart it: if we are right, the app should fail to start the services. And in fact:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_48584ef6-1fc6-4a21-8022-70e3cbd22945.png\" width=\"504\" height=\"248\" \/> <\/p>\n<p>As soon as we try, sure enough we get slapped with the same error as above: by now we know the cure: we just need to add the listen rule in the new scope. That should be really straightforward: we just follow the procedure above for adding a rule, right?<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_a2289502-6c59-436d-b666-a7a4c49aa104.png\" width=\"504\" height=\"293\" \/> <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_bbd62acf-5272-4757-ac4f-8ac1d6396d4a.png\" width=\"504\" height=\"424\" \/> <\/p>\n<p>In theory, that would be it: in practice, the MMC has a bug for which rules with input claims from accesscontrol.windows.net end up with a malformed issuer string. We need to fix it by using the portal, which BTW is the OFFICIAL way of managing your solution. For completeness, let\u2019s see the screenshots of the sequence you need to follow.<\/p>\n<p>Navigate to <a title=\"http:\/\/portal.ex.azure.microsoft.com\/\" href=\"http:\/\/portal.ex.azure.microsoft.com\/\">http:\/\/portal.ex.azure.microsoft.com\/<\/a> and sign in with your Live ID<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_d2791ed8-f1bf-44db-a313-b74d96ff2e17.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Choose your solution<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_71d4a8aa-cd98-40ea-9dc2-ec29195b8bbd.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Choose the ACS<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_1782db03-82bb-4385-8d25-669e89b13517.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Choose Advanced<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_42f154bd-7683-4044-a706-8eafcbbc0556.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Pick the ServiceBus scopes<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_9bf9301c-d267-4b73-9b39-72cc3e3c3c9f.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Pick the nested scope<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_203824e7-2a38-4a52-bdc3-6b1606c04e24.png\" width=\"504\" height=\"299\" \/> <\/p>\n<p>Edit the Listen rule<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_2eed03c0-a241-46e7-bf2e-0f4d7ddbe758.png\" width=\"504\" height=\"278\" \/> <\/p>\n<p>Note that the Issuer field contains accesscontrol.windows.net\/accesscontrol.windows.net. Change it to be just accesscontrol.windows.net. Hit save<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;border-top: 0px;border-right: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2009\/03\/image_26ec8452-950f-4406-a596-b0b6b3d34082.png\" width=\"504\" height=\"293\" \/> <\/p>\n<p>And you are up &amp; running! If you didn\u2019t do any typos, both phones &amp; laptop votes should again allow calls secured by fedid.net tokens.<\/p>\n<h1>Summary<\/h1>\n<p>This surely took a lot of screenshots! In this installment I tried to give you a feeling of how easy it is to get the ACS to accept tokens from trusted issuers; I have shown how you can easily call multiple services in your solution without having to re-enter your credentials multiple times; I also fiddled a bit with scopes, demonstrating how they can be used for applying your access control at a finer granularity. I hope this inspires you to try new things and play further with the ACS \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>digg_url = &#8220;http:\/\/blogs.msdn.com\/vbertocci\/archive\/2009\/03\/17\/a-visual-tour-of-the-net-access-control-service-part-2-fun-with-scopes-and-issuers.aspx&#8221;;digg_title = &#8220;A visual tour of the .NET Access Control service, part 2: fun with scopes and issuers&#8221;;digg_bgcolor = &#8220;#FFFFFF&#8221;;digg_skin = &#8220;normal&#8221;;digg_url = undefined;digg_title = undefined;digg_bgcolor = undefined;digg_skin = undefined; Here we are again. I am just back from Belgium\u2019s TechDays, and I can still savor the nice feeling you get&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1408,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[72,78,61,41,39,23,9,44,20,55],"tags":[],"class_list":["post-415","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-access-control","category-net-services","category-architecture-ws","category-azure-services","category-cardspace","category-federation","category-identity","category-techdays","category-the-cloud","category-windows-cardspace"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/415","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=415"}],"version-history":[{"count":0,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/415\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/1408"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}