Exercise 2: Customizing the Credentials Accepted by a Local STS

This is an optional exercise. Its purpose is to understand a bit more the structure of an STS project: however it is very probable that most of the times you will rely on existing STSes rather than having to write one, hence feel free to skip to exercise three if you are in a hurry.

In Exercise 1 we have shown how to generate a development STS in order to keep our application free from authentication-specific code and for feeding it with the claims we needed. The default structure of the auto generated STS does not really perform any authentication step, and just takes care of feeding the application with claims by following the proper protocols: the credential gathering page does not really validate the credentials you enter, and just goes ahead with the issuing process. For the purpose of developing our RP application this is enough, however if you’d want to use that STS as a starting point for writing your own there are a number of aspects that require to be expanded.

In this exercise we will modify an automatically generated development STS so that it will actually authenticate incoming users against an ASP.NET membership provider store, and it will source claim values from an ASP.NET profile and a Role manager store.

Note:
You should always take into account that the exercises in this lab are didactic tools meant to demonstrate how to use the technology, and the code you see here is not ready for production use.

Figure 25

The redirects & claims flow, showing credential check and claims sourcing in the STS

Task 1 - Configuring the STS

In this task you will configure the STS to use ASP.NET authentication mechanisms.

  1. Open Microsoft Visual Studio 2010 with administrator privileges. From Start | All Programs | Microsoft Visual Studio 2010, right-click Microsoft Visual Studio 2010 and select Run as administrator.
  2. Open the ClaimsEnableWebSite.sln solution file located in the %YourInstallationFolder%\Labs\WebSitesAndIdentity\Source\Ex2-ClaimsEnabledDifferentCredentials\Begin folder.

    Note:
    While it is not mandatory for the successful execution of this exercise, it can be interesting to gain some understanding of the structure of one development STS automatically generated by the Windows Identity Foundation. If you are a “pure” ASP.NET application developer, with no interest in security topics, you can safely skip this note and go on with the exercise steps.

    Expand the ClaimsEnableWebSiteEx02_STS project in the Solution Explorer and observe its structure:

    This is a very typical Forms authentication based website structure.

    The Login.aspx page is where the credential gathering happens.

    The Default.aspx page represents the entry point for applications to invoke the STS: there are protocols (in this case WS-Federation) that will redirect the user to this page whenever one application requires a token from our STS. This is how Default.aspx looks like in the designer:

    From this brief explanation of the structure of the STS project you can already guess which steps will be necessary for transforming the default development STS into one STS which leverages an ASP.NET membership store:

    - Modify the ASP.NET structure of the project: add the membership store and modify the login.aspx page so that it will use the appropriate credential gathering and session management methods

    - Modify CustomSecurityTokenService.cs, namely the GetOutputClaimsIdentity method, so that it will retrieve the claim values from the profile and roles stores.

  3. Open a Windows Explorer instance and browse to the folder %YourInstalletionFolder%\Labs\WebSitesAndIdentity\Source\Assets.
  4. Copy the membership database to the STS Web site. To do this, copy the App_Data folder from the Assets folder to % YourInstalletionFolder %\Labs\WebSitesAndIdentity\ Source\Ex2-ClaimsEnabledDifferentCredentials\Begin\ClaimsEnableWebSite_STS (if you continue working from previous exercise copy the App_Data folder to the correct STS Web site folder)
  5. Assign Write permission to NETWORK SERVICE (or IIS_IUSRS for Windows 7 and Windows Server 2008 R2) user for the % YourInstalletionFolder %\Labs\WebSitesAndIdentity\ Source\Ex2-ClaimsEnabledDifferentCredentials\Begin\ClaimsEnableWebSite_STS \App_Data folder. To do this, right-click the App_Data folder, select Properties, go to the Security tab and click Edit. On the Permissions for App_Data select the "NETWORK SERVICE" user and check the Write permission. Click OK on each dialog.

    Figure 26

    Assigning NETWORK SERVICE write permissions for App_Data

  6. Open the Web.Config file from the STS project (https://localhost/ClaimsEnableWebSiteEx02_STS)
  7. Add the following configuration under <system.web> to enable role and profile management with the BirthDate custom property.

    (Code Snippet – Web Sites And Identity Lab - Ex02 Membership Configurations)

    XML

    <system.web>
    <roleManager enabled="true" /> <profile enabled="true" > <providers /> <properties> <add name="BirthDate" type="System.DateTime"/> </properties> </profile>FakePre-04d23596a5a8479cb6bf3f1eeb5e9e8f-ef6da5a81864427eacf7fff36edbd22eFakePre-d6c42798fea04d0eaf1c064640049a13-6c0b04c8fa934be5b5b5517b0ea5bcaa

    Note:
    The STS project is already configured to use Forms authentication. In the following steps you will modify the login.aspx page so that it will leverage the standard ASP.NET Login control, which in turn will authenticate users against the membership provider store we added to the project.

  8. Open the Login.aspx file from the https://localhost/ClaimsEnableWebSiteEx02_STS project.
  9. Replace the HTML controls (table and p elements) with an ASP.NET Login control.

    ASPX

        ...
    FakePre-619c10ada9764ec08f3f98729337f94b-41338d339e1d44f08ec6b8dcb732ef67FakePre-18cc28d408bc476dab211060713993c7-eab5d53dca4d49588b2930074aeb75a2FakePre-ae782abd2ce747d3956de79c8c50804e-b191c0afce51425f91ed90f452871744FakePre-8ac3e1f3dfa84a27878b37db4e769347-05296d56defc4958ac6cea33569ae16cFakePre-a07bae0398f34dc295496ca152e62b89-dd228fce5ad84d2ba2f3315095a96daeFakePre-f158474dae6443c69837b1397c312284-9c37b8c0b000428f8e15b51ece7901efFakePre-be6f191a63464e3c9f7c46dbf9f20eec-f9fce8eadef14a51bbded6e5a46a803eFakePre-5acd6028723a427cab387f7e55ddaebd-0486176529484c1cbf096ddccc1f515cFakePre-d460dddf291d4666b698113ae15010a4-e4af8cd5c2ca40ee877573227833b9a9FakePre-ac93e1e7d9f24d899cecf95d866c1f5e-120c49ef89e64598ad4a77ce2fef7b16FakePre-be37caef718c47328fb249bb5d3e78c1-5c4c5072559e4a4194bf992504c24c66FakePre-2051d8c6309f47a5b8638aaaf789ef44-276e4e258d784fcaa44a8bebeb261116FakePre-9d60241812084adbbe04d7d7d76618a4-bf24d99600d9488d8f639ea3f406ddebFakePre-2697090e0940439fb736f57d2f344454-82f246664f9c454e9db9c0b0ebf8a2fcFakePre-83d2a5af3a4e44a3aec609446e8d5d3b-81950e388dd34eceb28edc6c78ddc821FakePre-b04d4b5d1e724be386e21563367db883-b18f9c23c4ac4075a9705cefeaf91aecFakePre-8064637aefe643f49e51a947977333de-b198c071efb545458d42654521c6bf88FakePre-917760e11a044175b52b933db76df0a1-2a80762a4f5940db988a2d7d1ee9eb97FakePre-5b5477f3529b4ffb8cc17c9e7ab7baa4-d3f84ffe11bc4480b6ea267d6cf2d96fFakePre-4be36200e72147ff9c70f4c487594dc8-681480ef81264761ae3981e28cab575eFakePre-440845965e2148f89a5aa88044bc4785-17ac23998aea4e1c9a87e56ccef2dff0FakePre-ff7fbc76fdd849559aa66a3e71aa4acb-132f763514fc400eb0be71e9ae3125a1FakePre-9ca2c5d04b4345fdbe7c04faef533efb-833debd0804446d88ec2442b12761ce3FakePre-73401cbea2584298bfbb4875f5818002-0ed47ab6c2d847138628c498cedc5eb2FakePre-fc6ad5ecde2d4456a911a0b658facbfd-2a88bfd3023041b7913573da8aa11d0bFakePre-848abc30e38041ee83d93f425a44b91e-a3db1548dabc49c88b2834cdb756aa55FakePre-4a07c5a773b74222ad09a1cab4c3dbb3-ceb69fd193f24a20a72cf33b5d576c5eFakePre-f646796556ce4a9aac9bf20dbfe0ffc6-63851c42663d4dec9c8549b3ae4c9618FakePre-0c883b1b0faf40749bd4e0443cb221cb-11b26b6aa46e4d97a0f320627f9fb74aFakePre-20020d370b494d15a7ff9b0fe2cf1041-2d8e9bbe22be4a0a95374d9e4027af64FakePre-a93593dd4e374e88b7bc965e84f971ca-6eb0912329e64c9789ecee20b3907143FakePre-d2a895d103d2434e868fcf60b1c6a00f-1ec58e04c49747f7b1d6a6da4ba9000aFakePre-f1e8ed155f424f0fbc7502ccab88dc2f-b6017a0a18ef426eae8a9ad73b16a101FakePre-074869b0163a423ba9eee9bf8a2aa6ad-2ac24af8cca04360943c95ef7c77e990 <asp:Login ID="loginPanel" runat="server"></asp:Login>FakePre-e810af1058c54698a23e81bad81dbabb-9211ea7e12684b9dbf0ab175c4ee3853FakePre-30de61daf4db47c08507e6f0a67c6696-4a682fd56c4f4656be6be2d1af86fb34FakePre-defd6e0ef96e45ac916c028d154ecf43-de855fc6cd464225a10a59f46104d892FakePre-59505159a6c04b95adf1dd5f1a3230e9-17637a4646d740c3beaa4362f628b5f3FakePre-db57b0d174a54856aa345fc46eba6202-5ee5e05f6084466283bf30f48cb48fd0FakePre-42f5f8d72ea846a8bd23d7b238809712-22a7d1b310e04cb79767c5f0e4b882edFakePre-cb015d3c32d74873ba30d7660d15eab9-309aa3960df641b2adfa9b05ad7c73afFakePre-969e6fbfbe3446dbba1a78866b22cde9-b1657db9898b48a7be54f7271b167ddbFakePre-ba9c91c6f0c64dd1847d64ff82b7a627-e3c29523a426498c845980fbfccb37c6

  10. Open Login.aspx.cs.
  11. Comment the Page_Load method.
    Note:
    Up to this point you have configured nothing related to Windows Identity Foundation. These are the usual changes done to use Membership provider in any website. In the following task you will take advantage of using SQL as the backing store and the Membership, Role and Profile providers to issue claims about the user as opposed to the hardcoded values we used in Exercise 1.

Task 2 - Using the Roles Principal

In this task you will change the STS to issue claims about the user coming from the principal and the Profile.

  1. Open CustomSecurityTokenService.cs on the STS project (https://localhost/ClaimsEnableWebSiteEx02_STS) under App_Code folder.
  2. Add the following using statements shown in bold.

    (Code Snippet - Web Sites And Identity Lab - Ex02 Add Using Statements)

    C#

    using System;
    FakePre-70a0c40f6d444634b9966e5bf9ceb919-124fe95533f54350bc32b5291b4a31b1FakePre-9ceeb4231d2e4f7098503f14cadfe3aa-8639c34e176c4725bd89cd7acf5ed117FakePre-d844eba2c6434b319556a8de0442cf91-2609cad86e874beebdd5055334eff20eFakePre-a6a095204853408f92dc5278069df338-806e90c8db964e3dad8cf62aabe3a350FakePre-c792168728b14404b7fd87cd2ca2eb63-4215bde6502a407191594f2f019f7a0eFakePre-6cdef0aa20e449dfaadcb53e4292b30f-a298e5b43a21425391ffc824ce74ee8dFakePre-e2bfddb8dd764d0db28e8b9e95309a40-c82432cb421445468f4eb54f51cb8d20FakePre-b5bcc2e9cedb462fa12ee7135e830b3d-8020c717035943948bc270d292825dcaFakePre-753aaa93bfeb4968b534afbc3b26a959-6bc2dfd819b7439e90d594e2655c691dusing System.Collections.Generic; using System.Linq; using System.Web;

  3. Remove the fixed roles “Manager” and “Sales” claims and add the role claims from the ClaimsPrincipal. To do this, update the method GetOutputClaimsIdentity with the following code shown in bold.

    (Code Snippet - Web Sites And Identity Lab - Ex02 Adding Role Claim)

    C#

    protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
    FakePre-454250f492134310a614d2c866bbb64f-b672f9c5e2fe4a66bd9a75809138a118FakePre-1e565968368d4c889b9b01b09c94481f-a7e9c12d2ba74fc2a3e0171fc0567d13FakePre-fabc43df917e40ce875d24de10a72594-cb9db7f7c4c8412a8c422b8b2a28c190FakePre-8407a3c4f0da4c16a380486bd6d4d975-c2cad83a527648a68664de11f537a0a0FakePre-001ab0fb9d03438db5d6dfac36c20393-e2f22f11556a45538eeb2126ebc9770fFakePre-b49c74480da74eb982d95bd45bf27839-c43beeec2d1844cf898be6434d9d4e5aFakePre-ccf669596f774160ab2e880a0ce1561e-c97945f28ba040a9bdcc768301309137FakePre-b27db731c5d54daebe5c8b539387d9ba-1aca62cdac3d4b05badab9fedf92cdb2FakePre-81f2abb9d6f04ff7b797b2d0af9bbb0b-9490c933ef11462cb6ef79e0ff515c2bFakePre-a0c476ba69a445c9b63724f7d8347397-8aeaebbb87484b5798053970bed225a0FakePre-54ee078254494632a6d16df2b3772ee0-bb2f7336f6194494984d12734b44fc55FakePre-714066763f3e43339f879cf28a925179-c6f95050fe63466197824194700c54bdFakePre-e0068ee8b3344fe3971ee878c4044fe1-b9745edd79044f83a6c563e4f5d6a9c8 IEnumerable<Claim> roleClaims = from claim in principal.Identities[0].Claims where claim.ClaimType == ClaimTypes.Role select claim; foreach (Claim roleClaim in roleClaims) { outputIdentity.Claims.Add(new Claim(roleClaim.ClaimType, roleClaim.Value)); }FakePre-364389b9f2ba4323b92b78daafb39d6e-7652130d9f664812921c37e948c9b559FakePre-cf0a668b2c2b4d2b8b95cc7567215087-5e087378d36b44c5b36f023fb1b0e8d6FakePre-daf118ae61654ee5966cb0718691cf27-b6ad98affa64416aa8b197dbb98fd853FakePre-ea4cb4796dbe415f8497757700a7f6b2-0b324b2d780646ed98a23a4a635a8c20FakePre-c6facf8bad2a4e4faf156b2ad5015e77-eacf068bbeb44f788cff3c52e1884d5f

  4. Comment the fixed "Birthday" claim in the GetOutputClaimsIdentity method.

    C#

    protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
    FakePre-bd0a38a1493b47729bfdf1a95354b2c5-cc1ca7a898d84cb78a0a0713dc92d7f6FakePre-3ef26270de9c40599aa8a04c7a740f13-31996a8583fe4c3ea6188c3740cf457fFakePre-c4e11ca38fa54692aded41340f2a337d-c0317baf0a654b2c8404c50d2724794a// outputIdentity.Claims.Add(new Claim(System.IdentityModel.Claims.ClaimTypes.DateOfBirth, "5/5/1955"));FakePre-1768809c65814685af8e8b27ab3cc72e-1cd4cad16aca4d23ac0e1e0edb5ac94aFakePre-9cc3b5c6c5e043ed893a2b3e1b7ca014-b89fedbd5fb54fc4ae0f3b6e617e2fa0FakePre-dd204805aa6a40199713fe9e44eed20e-0a05bce19edd4386aa2a0269b111d4eb

  5. Add the BirthDateProfile property. To do this, update the method GetOutputClaimsIdentity with the following code shown in bold.

    (Code Snippet - Web Sites And Identity Lab - Ex02 Adding Birth Date claims)

    C#

    protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)
    FakePre-4a6afb6d2d434661a72d8ced133ad4f8-1220f8f6ce734e1cb12693512ab2971dFakePre-dcb0c2bbcb3d4ab1b5cdf906cd0d53a5-07a943d688014ebda728474bec522a05FakePre-c29dd5634ad142b9bd530ae60b81edfd-77f75b0db8aa46188feb8d9b4635ac79FakePre-f5443b921c5640ddb722ab5666b0f6b7-5f5710924136447589c8faa0083003daFakePre-2211cd3607384cbd9defa2260535223d-3005330fa3d64988961f9792942660bbFakePre-1ad585f91dfa4063aeada1c96ef2e114-1c64c62db8f647c984a05329bde50871FakePre-d97ad41ad919418c91a79d24f5c703f7-6999f471c4b64cee92f938457772373eFakePre-e671aa8fe16340d6bcc8450bf3a83ac4-0a9fd19a7d9b44ff9b07b4a5377013ebFakePre-e0a1dc6161bb467cb95cb51c4b58590d-751165ac5f484718a7e604d9363151d3FakePre-7cb4c55fd8024712b4906e8f0b217b22-bf5d63d3d859477c84a356910f9e9117FakePre-7a3e111c97ba4331810a474e3270e90f-65a2fee18d1a4022841721cae1b0d75aFakePre-d06e21b275c14db2b0eec134ddf37424-7e09b9a0cdc043adb7abb12266be05d8FakePre-d15be38923904dad80c0b8a6cddc3248-a616e0f4d37e4d74a3f546c46a303ac9FakePre-ad579355dff84e9e945e602d32136945-4140c151c94c49358243086b7832bc32FakePre-4b65411b77544571bd753507c566bcd6-d4f4116788f448368b0984bd669c4d2cFakePre-7bd4bbb4ef1d4002a1ef4986162e3a2e-dd347401bf4f47808e25cf9e7605ceaaFakePre-061e638d87be4f7cb6741ebb028adec0-0e12026bc2564646b46c9038e07c1f2bFakePre-d98b3f15fcbf42e1b41b694d216c686e-74e979f8744d48cf8a71809d5caad367FakePre-54b52041b9314354b371aa7976151f79-2d7bb6181e054160b70c942d85e22f4aFakePre-91b005b321e7491c983512285338cbee-105c22e4032c4ae3877c33caec4cf874 DateTime birthdate = (DateTime)HttpContext.Current.Profile.GetPropertyValue("BirthDate"); Claim birthdateClaim = new Claim(System.IdentityModel.Claims.ClaimTypes.DateOfBirth, birthdate.ToShortDateString()); outputIdentity.Claims.Add(birthdateClaim);FakePre-5e885cb07b89460b898d607f1ec13b25-c78b9fda930641f79f67f31b01668aa7FakePre-9e8d9cb92ccc4cf3845208fe501bba73-d79d5f27cbf5472eae4c1868abf1c921FakePre-b8e9fba5530745bcabf5727ea1061749-ed1c127836a446e193c6beb59dfec4af

Exercise 2: Verification

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

Note:
If you are using the End solution to test the results without performing the exercise tasks, first, you have to give write permissions to NETWORK SERVICE (or IIS_IUSRS for Windows 7 and Windows Server 2008 R2) user for the App_Data folder in the STS project as detailed on the first steps of Task 1.

  1. Press Ctrl+F5 to run the solution (https://localhost/ClaimsEnableWebSiteEx02 project).
  2. When prompted for credentials, insert "invalid_user" in the User Name and Password fields.

    Figure 27

    Login rejected

    Note:
    If your SQL Express instance name is other than SQLEXPRESS, add the following configuration to the web.config under the Web Site https://localhost/ClaimsEnableWebSiteEx02 _STS (show in bold):

    <connectionStrings>

    <remove name="LocalSqlServer"/>

    <add name="LocalSqlServer" connectionString="data source=.\<YOURINSTANCESQLEXPRESSNAME>;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient"/>

    </connectionStrings>

  3. Now, log in with the John credentials (which is in Reader role).

    • User Name: john
    • Password: p@ssw0rd

    Figure 28

    Logging in with an existing user

    Figure 29

    Showing information based on name and dateOfBirth claims for john user.

  4. Browse to the secret page and you should get an Access Denied, because the user John does not have a claim Role with value Manager.

    Figure 30

    Access denied error page

  5. Close the Web browser.
  6. Open a new Web browser instance and navigate to the Web site again (https://localhost/ClaimsEnableWebSiteEx02).
  7. Now, log in with the Paul credentials (which is in Manager role).

    • User Name: paul
    • Password: p@ssw0rd

    Figure 31

    Showing information based on Name and dateOfBirth claims from Paul user

  8. Click on Go to secret page. Now you should be able to browse to the secret page.

    Figure 32

    Showing the secret page