Alik Levin's

Clarity, Technology, and Solving Problems | PracticeThis.com 

January, 2011

  • Alik Levin's

    Windows Azure AppFabric Access Control Service (ACS) v2– Returning Friendly Error Messages Using Error URL Feature

    • 5 Comments

    Programming Windows Azure - Programming the Microsoft Cloud

    Windows Azure AppFabric Access Control Service (ACS) v2 has a feature called Error URL that allows a web site to display friendly message in case of error during the authentication/federation process. For example, during the authentication with Facebook or Google a user asked for consent after successful authentication. If the user denies ACS generates an error that could be presneted to a user in a friendly manner. Another case is when there is a mis-configuration at ACS level, for example, no rules generated for specific identity provider which results in error generated by ACS.

    How to show friendly error message for these cases, branded with the look an feel as the rest of my website?

    The solution is using Error URL feature available through ACS management portal. ACS generated JSON encoded error message and passes it to your error page. You need to specify the URL of the error page on ACS management portal so that ACS will know where to pass the information. Your error page should pars the JSON encoded error message and render appropriate HTML for the end user. Here is a sample JSON encoded error message:

    {"context":null,"httpReturnCode":401,"identityProvider":"Google","timeStamp":"2010-12-17 21:01:36Z","traceId":"16bba464-03b9-48c6-a248-9d16747b1515","errors":[{"errorCode":"ACS30000","errorMessage":"There was an error processing an OpenID sign-in response."},{"errorCode":"ACS50019","errorMessage":"Sign-in was cancelled by the user."}]}

    Summary of steps:

    To process error messages from ACS complete these steps:

    • Step 1 – Enable Error URL Feature
    • Step 2 – Create Error Helper Classes
    • Step 3 – Process JSON Encoded Error Message
    • Step 4 – Configure Anonymous Access To The Error Page
    • Step 5 – Test Your Work

    Step 1 – Enable Error URL Feature

    To enable Error URL feature for your relying party:

    1. Login to http://portal.appfabriclabs.com.
    2. On the My Projects page click on your project.
    3. On the Project:<<YourProject>> page click on  Access Control link for desired namespace.
    4. On the Access Control Settings: <<YourNamespace>> page click on Manage Access Control link.
    5. On the Access Control Service page click on Relying Party Applications link.
    6. On the Relying Party Applications page click on your relying party application.
    7. On the Edit Relying Party application page notice Error URL field in Relying Party Application Details section.
    8. Inter your error page URL. This is the page that will receive JSON URL encoded parameters that include the error details.

    Step 2 – Create Error Helper Classes

    This step helps creating Error helpers classes for deserializing JSON encoded error messages.

    To create Error Helper Classes:

    1. Add class file and give it a name, for example, Error.cs.
    2. Implement the Error class as follows:
      public class Error
      {
          public string errorCode { get; set; }
          public string errorMessage { get; set; }
      }
    3. Add another class file and give it a name, for example, ErrorDetails.cs.
    4. Implement the ErrorDetials class as follows:
      public class ErrorDetails
      {
          public string context { get; set; }
          public int httpReturnCode { get; set; }
          public string identityProvider { get; set; }
          public Error[] errors { get; set; }
      }
    5. These classes will be used in the next step when processing error messages from ACS.

    Step 3 – Process JSON Encoded Error Message

    To process JSON encoded error message generated by ACS:

    1. Add an aspx web page to your ASP.NET application. And give it a name, for example, ErrorPage.aspx. It will serve as an error page that will process the JSON encoded error message sent from ACS.
    2. Add the following labels controls to the ASP.NET markup:
      <asp:Label ID="lblIdntityProvider" runat="server"></asp:Label>
      
      <asp:Label ID="lblErrorMessage" runat="server"></asp:Label>
      
    3. Switch to the page’s code behind file, ErrorPge.aspx.cs.
    4. Add the following declaration to the top:
      using System.Web.Script.Serialization;
    5. Add the following code to Page_Load method:
      JavaScriptSerializer serializer = new JavaScriptSerializer();
      ErrorDetails error = serializer.Deserialize<ErrorDetails>( 
      Request["ErrorDetails"] ); lblIdntityProvider.Text = error.identityProvider; lblErrorMessage.Text = string.Format("Error Code {0}: {1}",
      error.errors[0].errorCode,
      error.errors[0].errorMessage);
    6. The above code is responsible for processing JSON encoded error messages received from ACS. You might want to loop through the errors array as it might have additional more fine grained error information.

    Step 4 – Configure Anonymous Access To The Error Page

    To configure anonymous access to the error page:

    1. Open web.config of your application and add the following entry: 
        <location path="ErrorPage.aspx">
          <system.web>
            <authorization>
              <allow users="*" />
            </authorization>
          </system.web>
        </location>
      
    2. This will make sure you are not get into infinite redirection loop.

    Step 5 – Test Your Work

    To test Error URL feature:

    1. Login to http://portal.appfabriclabs.com.
    2. On the My Projects page click on your project.
    3. On the Project:<<YourProject>> page click on  Access Control link for desired namespace.
    4. On the Access Control Settings: <<YourNamespace>> page click on Manage Access Control link.
    5. On the Access Control Service page click on Rule Groups link.
    6. On the Rule Groups page click on the rule group related to your relying party.
    7. WARNING: This step cannot be undone. If you are deleting generated rules they can be easily generated once more. On the Edit Rule Group page delete all rules. To delete all rules check all rules in the Rules section and click Delete Selected Rules link.
    8. Click Save button.
    9. Return to your web site and navigate to one of the pages using browser.
    10. You should be redirected to your identity provider for authentication – Windows LiveID, Google, Facebook, Yahoo!, or ADFS 2.0 – whatever is configured for your relying party as identity provider.
    11. After successful authentication your should be redirected back to ACS which should generate an error since no rules defined.
    12. This error should be displayed on your error page that you created in step 2, similar to the following:

    uri:WindowsLiveID
    Error Code ACS50000: There was an error issuing a token.

    Another way to test it is denying user consent. This is presented when you login using Facebook or Google.

    Related Books

    Related Info

  • Alik Levin's

    Windows Azure AppFabric Access Control Service (ACS) v2 – Programmatically Adding Facebook as an Identity Provider Using Management Service

    • 0 Comments

    This simple walkthrough shows how to use Management Service of Windows Azure AppFabric Access Control Service (ACS) v2 to programmatically add Facebook as an identity provider. Complete walkthrough can be found here - Windows Azure AppFabric Access Control Service v2 - Adding Identity Provider Using Management Service.

    The code related to Facebook is cannibalized from the end-to-end SaaS sample - FabrikamShipping SaaS Demo Source Code.

    Code samples with other functionalities is available here - Code Sample: Management Service.

    Other ACS code samples available here - Code Samples Index.

    Code related to this post can be found here. Next I will call out changes and differences comparing to Windows Azure AppFabric Access Control Service v2 - Adding Identity Provider Using Management Service.

    To complete this walkthrough:

    1. Obtain Facebook application id and application secret. Instructions on how to do so can be found here - How To: Configure Facebook as an Identity Provider. Skip to Step 3 – Obtaining a Facebook Application ID and a Facebook Application Secret.
    2. Identity provider key is based on Facebook’s application id and application secret obtained in previous step. There is related code change:
      var facebookKeys = new[]
          {
              new IdentityProviderKey
                  {
                      IdentityProvider = facebook,
                      StartDate = DateTime.UtcNow,
                      EndDate = DateTime.UtcNow.AddYears(1),
                      Type = "ApplicationKey",
                      Usage = "ApplicationId",
                      Value = Encoding.Default.GetBytes(facebookAppId)
                  },
              new IdentityProviderKey
                  {
                      IdentityProvider = facebook,
                      StartDate = DateTime.UtcNow,
                      EndDate = DateTime.UtcNow.AddYears(1),
                      Type = "ApplicationKey",
                      Usage = "ApplicationSecret",
                      Value = Encoding.Default.GetBytes(facebookAppSecret)
                  }
          };
    3. Test your work by running the code and then logging in to Access Control Service Management Portal at https://portal.appfabriclabs.com/. Navigate to Identity Providers page and verify Facebook is added as identity provider.

    Related Books

    Related Info

  • Alik Levin's

    Windows Azure AppFabric Access Control Service v2 - Adding Identity Provider Using Management Service

    • 0 Comments

    This is quick intro to how to use Windows Azure AppFabric Access Control Service (ACS) v2 Management Service. In this sample I will show you what’s needed to add ADFS as an identity provider.

    Summary of steps:

    • Step 1 - Collect configuration information.
    • Step 2 - Add references to required services and assemblies.
    • Step 3 – Create Management Service Proxy
    • Step 4 - Add identity provider
    • Step 5 - Test your work

    The full sample with other functionalities is available here - Code Sample: Management Service.

    The simplified sample I used for this walkthrough is here.

    Other ACS code samples available here - Code Samples Index.

    Step 1 - Collect configuration information.

    1. Obtain Management Client password using ACS Management Portal. Login to the Access Control Service management portal. In Administration section click on Management Service link. On the Management Service page click on ManagementClient link (ManagementClient is actual username for the service). In the Credentials section click either on Symmetric Key or Password link. The value in each is the same. This is the password.
    2. Obtain signing certificate from your ADFS 2.0.
    3. Make a note of your namespace, AppFabric host name (for lab it is accesscontrol.appfabriclabs.com )
    4. You should have these handy. 
    string serviceIdentityUsernameForManagement = "ManagementClient";
    string serviceIdentityPasswordForManagement = "QL1nPx/iuX...YOUR PASSWORD FOR MANAGEMENT SERVICE GOES HERE";
    string serviceNamespace = "YOUR NAMESPACE GOES HERE";
    string acsHostName = "accesscontrol.appfabriclabs.com";
    string signingCertificate = "MIIDIDCCAgigA... YOUR SIGNING CERT GOES HERE";
    //WILL BE USED TO CACHE AND REUSE OBTAINED TOKEN. 
    string cachedSwtToken;

    Step 2 - Add references to required services and assemblies.

    1. Add reference to System.Web.Extensions.
    2. Add service reference to Management Service. Obtain Management Service URL.(https://<<YOURNAMESPACE>>.accesscontrol.appfabriclabs.com/v2/mgmt/service)
    3. Add the following declarations
      using System.Web;
      using System.Net;
      using System.Data.Services.Client;
      using System.Collections.Specialized;
      using System.Web.Script.Serialization;

    Step 3 – Create Management Service Proxy

    To create Management Service proxy:

    1. Using configuration information collected earlier instantiate the proxy:
      string managementServiceHead = "v2/mgmt/service/";
      string managementServiceEndpoint = string.Format("https://{0}.{1}/{2}", serviceNamespace, acsHostName, managementServiceHead);
      ManagementService managementService = new ManagementService(new Uri(managementServiceEndpoint));
      managementService.SendingRequest += GetTokenWithWritePermission;
    2. Implement GetTokenWithWritePermission and its helper methods. It adds SWT OAuth token to Authorization header of HTTP request.
      public static ManagementService CreateManagementServiceClient()
      {
          string managementServiceHead = "v2/mgmt/service/";
          string managementServiceEndpoint = string.Format("https://{0}.{1}/{2}", serviceNamespace, acsHostName, managementServiceHead);
          ManagementService managementService = new ManagementService(new Uri(managementServiceEndpoint));
      
          managementService.SendingRequest += GetTokenWithWritePermission;
      
          return managementService;
      }
      
      public static void GetTokenWithWritePermission(object sender, SendingRequestEventArgs args)
      {
          GetTokenWithWritePermission((HttpWebRequest)args.Request);
      }
      
      /// <summary>
      /// Helper function for the event handler above, adding the SWT token to the HTTP 'Authorization' header. 
      /// The SWT token is cached so that we don't need to obtain a token on every request.
      /// </summary>
      public static void GetTokenWithWritePermission(HttpWebRequest args)
      {
          if (cachedSwtToken == null)
          {
              cachedSwtToken = GetTokenFromACS();
          }
      
          args.Headers.Add(HttpRequestHeader.Authorization, string.Format("OAuth {0}", cachedSwtToken));
      }
      
      /// <summary>
      /// Obtains a SWT token from ACSv2. 
      /// </summary>
      private static string GetTokenFromACS()
      {
          // request a token from ACS
          WebClient client = new WebClient();
          client.BaseAddress = string.Format("https://{0}.{1}", serviceNamespace, acsHostName);
      
          NameValueCollection values = new NameValueCollection();
      
          values.Add("grant_type", "password");
          values.Add("client_id", serviceIdentityUsernameForManagement);
          values.Add("username", serviceIdentityUsernameForManagement);
          values.Add("client_secret", serviceIdentityPasswordForManagement);
          values.Add("password", serviceIdentityPasswordForManagement);
      
          byte[] responseBytes = client.UploadValues("/v2/OAuth2-10/rp/AccessControlManagement", "POST", values);
      
          string response = Encoding.UTF8.GetString(responseBytes);
      
          // Parse the JSON response and return the access token 
          JavaScriptSerializer serializer = new JavaScriptSerializer();
      
          Dictionary<string, object> decodedDictionary = serializer.DeserializeObject(response) as Dictionary<string, object>;
      
          return decodedDictionary["access_token"] as string;
      
      }

    Step 4 - Add identity provider

    To add Identity Provider:

    1. Add your identity provider as issuer (svc is an instance of a proxy to Management Service):
      Issuer issuer = new Issuer
      {
          Name = identityProviderName
      };
      svc.AddToIssuers(issuer);
      svc.SaveChanges(SaveChangesOptions.Batch);
    2. Add identity provider:
      IdentityProvider identityProvider = new IdentityProvider()
      {
          DisplayName = identityProviderName,
          Description = identityProviderName,
          WebSSOProtocolType = "WsFederation",
          IssuerId = issuer.Id
      };
      svc.AddObject("IdentityProviders", identityProvider);
    3. Create identity provider’s signing key based on the certificate obtained earlier 
      IdentityProviderKey identityProviderKey = new IdentityProviderKey()
      {
          DisplayName = "SampleIdentityProviderKeyDisplayName",
          Type = "X509Certificate",
          Usage = "Signing",
          Value = Convert.FromBase64String(signingCertificate),
          IdentityProvider = identityProvider,
          StartDate = startDate,
          EndDate = endDate,
      };
      
      svc.AddRelatedObject(identityProvider, "IdentityProviderKeys", identityProviderKey);
    4. Update identity provider’s sign in address:
      IdentityProviderAddress realm = new IdentityProviderAddress()
      {
          Address = "http://yourdomain.com/sign-in/",
          EndpointType = "SignIn",
          IdentityProvider = identityProvider,
      };
      svc.AddRelatedObject(identityProvider, "IdentityProviderAddresses", realm);
      svc.SaveChanges(SaveChangesOptions.Batch);
    5. Make identity provider available to relying parties the Management relying party.
      foreach (RelyingParty rp in svc.RelyingParties)
      {
          // skip the built-in management RP. 
          if (rp.Name != "AccessControlManagement")
          {
              svc.AddToRelyingPartyIdentityProviders(new RelyingPartyIdentityProvider()
              {
                  IdentityProviderId = identityProvider.Id,
                  RelyingPartyId = rp.Id
              });
          }
      }
      svc.SaveChanges(SaveChangesOptions.Batch);

    Step 5 - Test your work

    To test your work:

    1. Log on to Access Control Service Management Portal.
    2. On the Access Control Service page click on Rule Groups link in  Trust Relationships section.
    3. Click on any of the available rules.
    4. On the Edit Rule Group page click on Add Rule link.
    5. On the Add Claim Rule page choose newly added Identity Provider from the dropdown list in the Claim Issuer section.
    6. Leave the rest with default values.
    7. Click on Save button.
    8. You have just created passthrough rule for the Identity Provider and if no error returned chances you are good to go.

    Related Books

    Related Info

Page 2 of 3 (8 items) 123