Exercise 3: Invoking a WCF Service on the Backend via Delegated Access

In Service Oriented Architectures, the composition and chaining of services are the base mechanisms that allow the reuse of existing services in order to create higher-level functionality. One recurring problem of composition has to do with access control: how do you make sure that the permissions granted to the original caller are honored though the layers of multiple services calling other services? The practice of relying on trusted subsystems, in which the user is verified just at the first layer and all the calls to the deeper layers are authenticated against applicative credentials, can be very risky; other mechanisms, such as Kerberos constrained delegation, have infrastructure requirements that are not always easy (or possible) to enact. Windows Identity Foundation provides a solution to this problem, by allowing a service to invoke another service by presenting a delegated token.

From an architectural point of view, Windows Identity Foundation achieves this by leveraging the ActAs mechanisms defined in the WS-Trust protocol. The service handing the original call from the user requires a token to an STS using its own application credentials, however it also attaches to the request the token that the current user sent in order to authenticate with the original service. The STS processes the request and issue a delegated token, which in turn the original service uses for invoking another web service acting as the user.

From the practical point of view, this means that the WCF developer needs to follow few extra steps before calling the backend service he needs. In the following exercise we will demonstrate exactly that, showing how to augment the solution we built in the former exercises with a delegated call to a backend service.

Figure 23

The identity of the original caller flows through two layers of services, thanks to the ActAs capabilities of ActAsSTSEx03

Task 1 - Opening the Solution

  1. Open Microsoft Visual Studio 2010 with administrator privileges. From Start | All Programs | Microsoft Visual Studio 2010, right-click Microsoft Visual Studio 2010 and choose Run as administrator.
  2. Open the WeatherStation.sln solution file located in the %YourInstallationFolder%\Labs\WebServicesAndIdentity\Source\Ex3-InvokingViaDelegatedAccess\Begin folder.
  3. In Solution Explorer, examine the projects that compose the beginning solution.

    Figure 24

    Exercise initial solution

    • https://localhost/ActAsStsEx03: a pre-configured STS capable of issuing delegated tokens
    • https://localhost/IdentityProviderStsEx03: a development STS which plays the role of the identity provider in our scenario; it will issue the tokens that will be used from the client for calling the first service in the chain, WeatherStationServiceEx03
    • https://localhost/SatelliteImagesServiceEx03: a service that returns satellite images; it will not be invoked directly from the client; instead, it will be called with delegated credentials by WeatherServiceEx03, which will include the results (if any) in its own return message to the client
    • https://localhost/WeatherStationServiceEx03: a service that returns weather forecast information
    • WeatherStationClient: a WinForms client application that consumes WeatherStationServiceEx03

Task 2 - Adding a Reference to the Backend Service

  1. In Solution Explorer, right-click the https://localhost/WeatherStationServiceEx03/ project and select Add Service Reference.

    Figure 25

    Adding a Service Reference

  2. In the Add Service Reference dialog, click Discover. In the Services panel, select SatelliteImageServiceEx03/Service.svc and click OK.

    Figure 26

    Selecting the SatelliteImageServiceEx03

    Note:
    Notice that the service reference has been added to the project and the App_WebReferences folder was created with the ServiceReference1 reference.

  3. Open the Web.config file of the https://localhost/WeatherStationServiceEx03/ project.
  4. Locate the system.serviceModel/client/endpoint element and replace the machine name with localhost in the address attribute (address="https://localhost/SatelliteImagesServiceEx03/Service.svc").

    XML

    <system.serviceModel>
    FakePre-6689d0169ad44437bf11fbc30e6487cc-b52659d927ca41118865eb5fc5915fd2 <endpoint address="https://localhost/SatelliteImagesServiceEx03/Service.svc"FakePre-35135c3e9b61414996c7d5bcaa9ac426-f68b5040c84b49b18bcaa2a4e2ecc12bFakePre-b393b413439e464e8a74f8fe914e1495-6e63828237d848df9fed673ad6e3cde8FakePre-989e366fbcb948ff8075f7cf571b1e21-bdd78aac59a24ba4bfb7622bc5afd33fFakePre-9a31596e51a8462bbf5703af9a7a935b-8bd8729e71ba4d86acdd05d8a3d7abc4FakePre-1d19bf4346934df29b68f1c2a1ac79b9-a81646be01a244ea9a93e9084bb3df75

  5. Locate the system.serviceModel/bindings/ws2007HttpBinding element and paste the following binding shown in bold.

    (Code Snippet – Web Services And Identity Lab - Ex03 Configure IssuedTokenBinding)

    XML

    <system.serviceModel>
    FakePre-885ebc1b88074775851e3d608fe1d243-bb6ee3ed7d944493a797d8b1f8123b36FakePre-743f8b722cdb415586e1bc5727d9e9a9-1a8a4fe7dda34e32a0a7b2b54d7a1831FakePre-6a425daf80a948048ff849f4f14892c4-19a26388650146b9bc9319d5024b45d0FakePre-33e31ee3769d42c189ebc07e98e2014a-2f199f20aeec462287747c1430b929f1FakePre-2bd197bb1e1f454da46673257b96e203-39b1d071a8a94bd0adaf5759ddf3ab52FakePre-48decef2f4674986899b0652a37bb616-8a42a352947c459c982e545bfff1b5dbFakePre-b3167a7c701f43e0a7706bce41a21a71-ec0a0f2232f74b1e9295c8cd4fc5165bFakePre-637899cdf96b43a9bfdc545159301558-cd687c9498e1418d9609aceb738a589cFakePre-76b03c1f38fb4916ae049afa8033360f-88c919b5100c475c9a100f706b76032b <binding name="IssuedTokenBinding"> <security mode="TransportWithMessageCredential"> <message clientCredentialType="Windows" establishSecurityContext="false" /> </security> </binding>FakePre-d0f0c9ce026f4effbdeae0fcb7c9f1c9-74262cb0de9f4233ba6d6f79352ab1c4FakePre-bde9699e8ac5431db3e2bf395c9fd82e-60f7204a96824d21b42bf85cfac72186FakePre-2470c90ac970498cb831167ab0da7b6c-e9b296d860f1499daba422bf41139fd6FakePre-2f3c0bfbbd2c42acb0a699794e4085bf-16ae015b60ca4aca91bd1a6eea607fd6FakePre-dd88a4e98d2d473ea30706cc7a51bbb4-c470b512296d48239f341c4d9cb76f0e

  6. Locate the CustomBinding_IService binding element (inside system.serviceModel/bindings/customBinding) and add the following settings to the issuer element (security/issuedTokenParameters/issuer) to use the binding from the previous step.

    (Code Snippet – Web Services And Identity Lab - Ex03 Configure Endpoint)

    XML

    <system.serviceModel>
    FakePre-8ae1f4fee75f474aa50036216b02a9f9-b58a4e8c12a34d22b049b338b39ca8d9FakePre-7202fd1d25a1431da03f9e9e9261b01e-725b90057e84474bb3511f0006c0d908FakePre-2f4b2caf4c644e5b848ce463b8a0e542-2c96f817800b4908b9a7cdcbc0390fdcFakePre-87e3b26e859f4cd58b76a6f36c9ae6a8-6feb6c620f0944219ba3625be5ecd727FakePre-5d867a85b25a4b68a7b68bfc5d52f0b2-100c3fcc87854665b264341ea4d4d6d4FakePre-6040b447811a4e0ab11666d4d82f48da-6b2bd8ba07404cedbaf00c1ab06c3426FakePre-554a84b094a8422c8c3f9bfd12de00ca-c043d4a291d8460e86dfc2c86baca7c5FakePre-d99e50a1fdfd422c932c02cd7fa3f6cc-d3a32d979427496d88268f4cafb1bea0FakePre-c2ea686402b746e8a4cfc3d00f63ceae-b9cb500de1334680969d792a8bfa6bf5 binding="ws2007HttpBinding" bindingConfiguration="IssuedTokenBinding"FakePre-734eb6e576484857bb3922402fe7b354-653f558ff7d0407d921c614778bad4d1FakePre-300e864b1585468a92f74b60a427f145-8723892ceb4e474ea5a72ccaa5150951FakePre-919a1cccfae747ec94cd25761231e035-b91ac89486d2438d86775695fe849613FakePre-c94b1bdaf6a64cb08d3ce9b837e1d878-02ba92120b1542be8cebf47e8f8ae5b0FakePre-79f687e376ce4eaeb330e440a5fdc3ba-25995fc1093a4d96b349645264901736FakePre-0e7e9adf13ba491480ff7a2ec0568dea-894e10da1c9a48f6973ece6f5ad3b631FakePre-995d80d930c84d42935411e66f520ab5-772d898582e04c119fef1949a32f5f8cFakePre-0e5b73902e5842cdbc226cfb2b51d91e-ede95cfb669441cbac828d2ab1a05039FakePre-1206b9c3ea42454e920a2af1d298db36-60c50acfc67c450fa6ca6c40ba37ef98FakePre-b977bc686bd14e58ac0900ab4d3af44d-cd0eff62b216452e8b605b844bcb3da2FakePre-44b6e9801ac8449dbd7dfdb819108255-46a4cb7de8b643f1bc17158190e3d8a0FakePre-c9a74e05700f4c87b75b377c795976ef-37217ffd1ff94201852648bfa22349eeFakePre-91e17b4b38ba485e9eb2c7798e4c7a4d-e26d73f1587c4ffa97c7ba7b5dda4f0fFakePre-c8a4f514291245f2bcc36b2716b793bd-7e11e50f3dab4e4390960012a005f40c

Task 3 - Calling the Backend Service

  1. Open the App_Code/Service.cs file from the https://localhost/WeatherStationServiceEx03/ project.
  2. Add the following using statements.

    (Code Snippet – Web Services And Identity Lab - Ex03 Service Usings)

    C#

    using System.Collections.ObjectModel; using System.IdentityModel.Tokens; using System.ServiceModel; using System.ServiceModel.Security; using System.Threading; using Microsoft.IdentityModel.Claims; using Microsoft.IdentityModel.Protocols.WSTrust;

  3. Paste the following snippet at the beginning of the GetForecast method to call the SatelliteImageService.

    (Code Snippet – Web Services And Identity Lab - Ex03 Calling The SatelliteImageService)

    C#

    protected WeatherResult GetForecast(int days, int zipCode)
    FakePre-addb33f83e164c28aab3586e3c43d6f0-0cdcaeb4577945efa9492de715c47924 IClaimsPrincipal principal = Thread.CurrentPrincipal as IClaimsPrincipal; SecurityToken callerToken = principal.Identities[0].BootstrapToken; // We expect only one identity, which will contain the bootstrap token. if (principal != null && principal.Identities.Count == 1) { callerToken = principal.Identities[0].BootstrapToken; } ChannelFactory<ServiceReference1.IServiceChannel> factory = new ChannelFactory<ServiceReference1.IServiceChannel>("CustomBinding_IService"); factory.ConfigureChannelFactory(); // Create and setup channel to talk to the backend service ServiceReference1.IServiceChannel channel; // Setup the ActAs to point to the caller's token so that we perform a delegated call to the backend service // on behalf of the original caller. channel = factory.CreateChannelActingAs<ServiceReference1.IServiceChannel>(callerToken); // Call the backend service and handle the possible exceptions byte[] image = null; try { image = channel.GetSatelliteImage(zipCode); } catch (SecurityAccessDeniedException) { channel.Abort(); }FakePre-b3fddf75b7d54c6888164652347b3e1f-799bf09696504f32bd702eaa479a8ca2FakePre-d969ba7fcd414476840a8c1781551387-05176c5879114c7c971a963f45496efbFakePre-d03ab6ee96ae4c56b453ff7d6856028d-4c7e41869ded485693c7853b0c3af5ecFakePre-4b80965c9b51450cae6bda560941a73e-aa22986a0d5446e686241b5b2c198c5cFakePre-bdff9b94da554d1892b7e733c83e919f-334ac79134ea4929ac3cda92d36a81d3FakePre-217b9191a27b4db3aa05c5ffcb639d1a-a19c983747e14d79aa6208cc47d2c48dFakePre-aedd19b2862a46b5aeeaae7623454f38-03c3aef6c3f3413486524d00a37057e4FakePre-c19da32de2ab4eb9a27454b46806a293-e76d0ff1605049f68d225b13ba7c0501FakePre-62d0cf658c0546239795b87146e59736-6be573b7a71045289b7694b337c36593FakePre-9d787cda3d044d34a3768cbafa996bb8-246b4c1407694e7dab5453417a123fecFakePre-8af3fa621e164746986d03f9145b6ee7-99dcec4bb5d348479b1b35e99e1f088a

    Note:
    Let us examine the code above. First, you are extracting the so called “bootstrap token” from the ClaimsPrincipal. This is a token issued by IdentityProviderStsEx03 that the service received with the call from the client application.

    Once you obtained the bootstrap token, you need to inject it in the call to SatelliteImagesServiceEx03 so that it will be used (along with WeatherStationServiceEx03 application identity credentials) to obtain a token from the ActAs STS, which in turn will be used to invoke the desired service. The mechanism provided by Windows Identity Foundation to implement the above is the CreateChannelActingAs extension method.

  4. Open the Web.config file of the https://localhost/WeatherStationServiceEx03 project. Locate the service element in the microsoft.identityModel section, insert a new attribute named saveBootstrapTokens and set its value as true.

    XML

    <microsoft.identityModel> <service saveBootstrapTokens="true"> <audienceUris> <add value="https://localhost/WeatherStationServiceEx03/Service.svc"/> </audienceUris>

  5. In the https://localhost/WeatherStationServiceEx03/ project under the App_Coder folder, open the Service.cs file, and then paste the following snippet at the end of the GetForecast method to return the image from the service.

    (Code Snippet – Web Services And Identity Lab - Ex03 Returning The Satellite Image)

    C#

    return new WeatherResult
    FakePre-7ac52c123a3b42bbb1c35e3c276281e6-242b9a0dfe5b4021986bf241e730eb0fFakePre-4883377bb3454d91b026cca1dfd26df8-14cb1e3d2d314c4c8af49fe6e0d200e1 SatelliteImage = imageFakePre-053b60d55327424a8aa9088ca71a75c8-6f6daaf3e71048858cdee96194283c1c

  6. Compile the solution.

Exercise 3: Verification

In order to verify that you have correctly performed all the steps in exercise four, proceed as follows:

  1. In Solution Explorer, right-click the WeatherStationClient project and select Set as StartUp Project.
  2. Start debugging by pressing F5.

    Figure 27

    Client application

  3. Enter any integer value in the ZIP code textbox.
  4. Click the Get 3 days button; when prompted for credentials enter the username "john" and the password "p@ssw0rd".

    Figure 28

    John gets the forecast

    Note:
    Since john does not have access to the SatelliteImageService, he is unable to retrieve an image from the service and the Show Satellite button appears disabled.

  5. Click the Get 10 days button again; when prompted for credentials enter the username "paul" and the password "p@ssw0rd".

    Figure 29

    Paul gets the forecast

  6. The Show Satellite button is now enabled, which suggests that the call to obtain the extra data succeeded. Click the Show Satellite button and you will see the image from the SatelliteImageService.

    Figure 30

    Satellite image

    Note:
    Since paul has access to the SatelliteImageService, he is able to retrieve the satellite image from the service.