Invoking the ACS management service programmatically

Introduction

As demonstrated in my previous posts, the ACS can be used to realize authentication and authorization mechanisms in Windows Azure. As Microsoft explains it, most developers are not identity experts and would not want to find themselves spending a lot of time into the inner workings of these mechanisms (source).
The ACS management portal can be a convenient way to specify security settings for Windows Azure applications. By merely a few mouse clicks one could set up an Identity based security mechanism that can be used by a Windows Azure application.

However, when considering a real world enterprise scenario where often more than one environment exists and each of these environments can have multiple Windows Azure applications, using the management portal can become a tedious task.
Luckily, we can use the ACS management service for this purpose. The ACS management service allows us to programmatically access and configure the ACS.

In this post, I will show how to create a simple console application that uses the ACS management service in order to edit these settings.

Prerequisites

The following components have been used in order to realize this blog post:

  1. Visual Studio 2012
  2. .NET Framework 4.0 and 4.5
  3. The latest Windows Azure tools (Here, October 2012 v1.8.51019.1603 is used)
  4. A Windows Azure account
  5. A running Access Control Service
  6. A running Facebook app. You can create them for free on: https://developers.facebook.com
  7. Source code used in this example.

Analysis

In order to understand which settings should be added and where these settings are located in the ACS management portal, we will start in creating a new ACS namespace and identify these settings.
Next, a console application will be created in Visual Studio that will be the configurator for these settings.

Note that a full blown Visual Studio solution to manage ACS settings is available at MSDN -> http://code.msdn.microsoft.com/Windows-Azure-AD-Access-0dcde385

The console application in this post is a stripped down and simplified version of the ManagementService project in the before mentioned MSDN link in order to show some of the key features the ACS management service has to offer.
Analogous to the CodePlex solution, constants will be defined in order to store the connection settings. For demonstration purposes, the password will be stored in the constants as well.
In the next steps, different settings will be added and coupled in order to realize the desired functionality.

Steps

  1. Accessing the ACS portal
  2. Creating a console application and add service reference
  3. Creating ACS management portal constants
  4. Download the ACS samples
  5. Connecting to the management service
  6. Adding identity providers
  7. Adding a relying party application
  8. Adding a rule group
  9. Coupling a rule group to the relying party application
  10. Creating a service identity

Accessing the ACS portal

In this example, I will use the following ACS: CorradinACSDemo

After having navigated to https://CorradinACSDemo.accesscontrol.windows.net the following screen is shown:

If you click on the Identity providers, by default, the Windows Live ID provider will be listed. Both the Relying pary applications and the Rule groups are empty initially.
In the next sections we will see how we can programmatically add these settings.

Creating a console application and add service reference

After having started Visual Studio 2012, create a new project and select “Console Application”.

In this example, we use “ACSConfigurator” as the name of the application.
In order to use the ACS management service, it has to be added to the solution by adding a service reference. This URI can be found in the application integration menu in the ACS management portal.

After clicking on “OK”, the service definitions will be added to the solution in the “Reference.cs” file.

Creating ACS management portal constants

Create a new static class “Constants.cs” with constants as shown below.

/// <summary>
/// Defines sample constant values for demonstration purposes.
/// These values need to be changed depending on the environment.
/// </summary>
public static class Constants
    {
        public const string ServiceIdentityUsernameForManagement = "ManagementClient";
        public const string ServiceIdentityPasswordForManagement = "[Your Password Here]";
        public const string ServiceNamespace = "corradinacsdemo";
        public const string AcsHostName = "accesscontrol.windows.net";
        public const string AcsManagementServicesRelativeUrl = "v2/mgmt/service/";
    }
}

You can find the values of the first two constants in the ACS Management Portal under “Management Service”. The first constant is the Name of the management service and the second constant is the password. This can be seen when clicking on “Password” -> “Show Password” in the portal as shown below.

Download the ACS samples

As mentioned before, the ACS management service samples can be downloaded at http://code.msdn.microsoft.com/Windows-Azure-AD-Access-0dcde385.
For this demonstration however, adjustments have been made in order to allow the console application to be used for different environments.

I will not go into too much detail regarding the management service source code, since this can be found on MSDN.
The solution for this demonstration can be found in the source code section below.

Connecting to the Management Service

In the main method of the “Program.cs” file the following code is added:

//Define the Uri to connect to the management service.
string managementServiceEndpoint = String.Format(
	CultureInfo.InvariantCulture, "https://{0}.{1}/{2}",
	Constants.ServiceNamespace,
	Constants.AcsHostName,
	Constants.AcsManagementServicesRelativeUrl
);
 
IdentityProviderHelper identityProviderHelper = new IdentityProviderHelper(managementServiceEndpoint);

First, the endpoint is defined. The IdentityProviderHelper takes this as an input argument, since this class will create a new management service based on this endpoint for each update action. The careful reader might ask why you cannot use one management service instance for all operations.
The reason behind this is that when you have multiple update operations on the same target (in this case the identity provider) and execute these operations as a batch, you will get an ACS60004 version conflict error. This error states that you cannot update an identity provider with the same name (in this case the issuer name) as specified before. A unique issuer name is needed. When creating separate management services, this error will not occur.

As can be seen, it is straightforward to add identity providers programmatically. The reason that Facebook identity provider needs more settings is that it uses Facebook Connect as opposed to OpenID. The latter is used by Google and Yahoo!.

Adding identity providers

//Add three identity providers
identityProviderHelper.AddFacebookIdentityProvider(Constants.FaceBookIP.DisplayName, Constants.FaceBookIP.ApplicationId, Constants.FaceBookIP.ApplicationSecret, Constants.FaceBookIP.ApplicationPermissions);
identityProviderHelper.AddOpenIdIdentityProvider(Constants.GoogleIP.DisplayName, Constants.GoogleSignInUri);
identityProviderHelper.AddOpenIdIdentityProvider(Constants.YahooIP.DisplayName, Constants.YahooSignInUri);

As can be seen, it is straightforward to add identity providers programmatically. The reason that Facebook identity provider needs more settings is that it uses Facebook Connect as opposed to OpenID. The latter is used by Google and Yahoo!.

The Facebook and open id calls, call extension methods of the management service. In short, these methods create an Identity provider and set the WebSSOProtocolType to Facebook and OpenId respectively. Finally, the service method “AddRelatedObject” is called, to set the properties of the identity providers (such as the sign in address, application id and application secret).
More information on how to configure the ACS management service can be found on: http://msdn.microsoft.com/en-us/library/windowsazure/hh135147.aspx

Adding a relying party application

Creating a relying party application requires the user to fill in three sections:

  1. Relying party application settings
  2. Authentication settings
  3. Token signing settings

Note: For SAML, a fourth option (Token encryption) is added, but we will skip it in this example.

The following code is added:

//Add a relying party application
var relyingPartyApplicationsHelper = new RelyingPartyApplicationsHelper(managementServiceEndpoint);
 
relyingPartyApplicationsHelper.CreateRelyingParty(
	Constants.MyRelyingPartyApplication.displayName, 
         Constants.MyRelyingPartyApplication.Realm, 
         Constants.MyRelyingPartyApplication.ReturnUrl, 
         Constants.MyRelyingPartyApplication.TokenFormatEnum, 
         Constants.MyRelyingPartyApplication.RequireEncryption, 
         Constants.MyRuleGroup.displayName, 
         Constants.MyRelyingPartyApplication.TokenFormat
);

The relying party application:

//Sample Relying party application
public static RelyingPartyApplication MyRelyingPartyApplication = new RelyingPartyApplication() { 
	displayName = "My relying party application", 
         Realm = "http://127.0.0.1", 
         ReturnUrl = string.Empty, 
         TokenFormatEnum = RelyingPartyTokenType.SWT, 
         RequireEncryption = false, 
         TokenFormat = new SWTTokenFormat(new SWTTokenSigningSettings(new SymmetricKeyTokenSigning())) 
};

The signature of the helper method is shown next:

public void CreateRelyingParty(
	string displayName, 
	string realm, 
	string returnUrl, 
	RelyingPartyTokenType tokenFormatEnum, 
	bool requireEncryption, 
	string ruleGroupName, 
	ITokenFormat tokenFormat, 
	int tokenLifetime = 600
)

What is important to notice is that there are two token formats specified in the parameters. I added the “ITokenFormat” interface, so that depending on the format (SAML, SWT or JWT) the relying party is created. The “tokenFormatEnum” is an enumeration of the three format types.
Furthermore the optional “tokenLifetime” parameter takes the default value of 600 seconds if not specified by the caller.

I would like to highlight one line of code in this method, before moving on to the next section:

//Adds the specified token signing settings to the relying party.
tokenFormat.tokenSigningSettings.tokenSigning.AddTokenSigningSettingsToRelyingParty(svc, relyingParty);

In combination with the “TokenFormat” parameter in the sample relying party application constants, it is not possible to create inconsistent settings. For example adding an X.509 certificate to a SWT token in its signing settings.
Furthermore, I believe it is easier to extend functionality of the different token format classes.

Currently, only SWT and symmetric signing is supported, but this can be easily extended adding the code on http://msdn.microsoft.com/en-us/library/windowsazure/hh135144.aspx#BKMK_6 to the interface implementation classes in the solution.

Adding a rule group

The addition of a rule group is done while creating a new relying party application as shown below:

// Create a rule group and you can follow the 'Rule' sample code to add rules to it as needed. 
RuleGroup ruleGroup = svc.RuleGroups.Where(rg => rg.Name == ruleGroupName).FirstOrDefault();
if (ruleGroup == null)
{
	ruleGroup = new RuleGroup()
         {
         	Name = ruleGroupName
         };
	svc.AddToRuleGroups(ruleGroup);
}

This code is appended after the code shown previously in the CreateRelyingParty method.

Coupling a rule group to the relying party application

Appended to the previous code is the following line:

svc.AssignRuleGroupToRelyingParty(ruleGroup, relyingParty);

This is an extension method defined in the source code mentioned in the “Analysis” section.

Creating a Service Identity

The final step is to create a service identity. In the ACS management portal this is straightforward.

After having specified a name and the type of credentials, the service identity is created.
Realizing this programmatically can be done as follows.

ServiceIdentityHelper serviceIdentityHelper = new ServiceIdentityHelper(managementServiceEndpoint);
serviceIdentityHelper.CreatePasswordServiceIdentity(Constants.MyNewServiceIdentity.Name, Constants.MyNewServiceIdentity.Password);

In this example, a password based service identity is created.

 

Source code

Conclusion

Adding ACS components programmatically saves the burden of clicking through the portal and allows more flexibility when considering different environments.
Using the solution, it is fairly easy to create an application that manages ACS settings programmatically.
In addition, the solution (in particular the relying party application settings) allows for extendibility by implementing the classes that derive from the different interfaces.

As always comments/suggestions/improvements are most welcome.

One thought on “Invoking the ACS management service programmatically

Leave a Reply