For those of you who were able to make it to my presentation at TEC 2011 (State side), I promised a blog entry going into some more technical detail on the Ensynch Accelerated SQL XMA (coming soon). If you are interested in the slides I presented you can get them here. Jeremy also had another suggestion that I will be trying out, so keep an eye out, I will let you know how it goes!
Thursday, May 26, 2011
Friday, April 22, 2011
File Based Management Agents In MIIS/ILM/FIM
I had a recent need to really compare the capabilities of each of the file based Management Agents in FIM. Can you name all five? Don't worry, I won't leave you hanging, they are:
- Attribute-value pair text file
- Delimited text file
- Directory Services Markup Language (DSML) 2.0
- Fixed-width text file
- LDAP Data Interchange Format (LDIF)
Here are some of the things that they can and can't do (this is for you Joe) and just for kicks, I also added in the SQL MA. If you are using one of these file types in an Extensible Management Agent (XMA), the following still applies:
| Multi-valued Attributes | Attribute Level Updates 1 | Multi-valued Level Attribute Updates 2 | |
| Attribute-value pair | YES | NO | NO |
| Delimited | YES 3 | NO | NO |
| DSML | YES | NO 4 | NO |
| Fixed-width | YES 3 | NO | NO |
| LDIF | YES | YES | ON IMPORT ONLY 5 |
| SQL MA | YES | YES | NO 6 |
Okay, now for the caveats (can’t get away without some of those):
- An Attribute Level Update implies that a delta import can contain only the attribute that has changed (along with the other required columns, like the type of change and the anchor)
So, here’s what that might look like. Suppose I have a user with the following attributes:
ID: 12345 Name: Sarah Status: Active Phone: 555-123-4567
If Sarah’s phone number changes to 555-987-6543, I can simply tell FIM something like:ID: 12345 Type Of Change: Update Phone: 555-987-6543
This has the advantage of giving FIM less work to do to determine what has changed on the records being imported and greatly speeds up delta imports.
- A Multi-valued Level Attribute Update supports adding and deleting specific values from a multi-valued attribute
Let’s take another look at Sara’s record:
ID: 12345 Name: Sarah Status: Active Phone: 555-123-4567 Phone: 555-456-7890
Now, Sarah has two Phone numbers, or a single attribute with multiple values. With multi-value level attribute update support, we can do things like add a new phone number to the list, delete a phone number from the list or update a phone number (in essence by doing an add of the new value and then a delete of the old one):ID: 12345 Type Of Change: Add Phone: 555-987-6543
Without this support, the source system would be required to do a “replace” action and provide FIM with all of the current values at the time of import which FIM will use to override all the values that it has for that attribute. So if we start with Sarah’s record as listed just above and add the phone number 555-987-6543 and remove the phone number 555-123-4567, we would have to pass:
ID: 12345 Type Of Change: Replace Phone: 555-987-6543 Phone: 555-4567-7890
As with attribute level updates, multi-valued level attribute update can greatly reduce the amount of work that FIM needs to accomplish. To illustrate, just imagine applying this scenario to attributes like member on an AD group that can have thousands of values.
- Using a multi-valued attribute in a delimited or fixed-width file requires the use of a header on the import file
So for a comma delimited file this would look like:
ID, NAME, PHONE, PHONE, PHONE
12345, Sarah, 555-123-4567, 555-987-6543, 555-456-7890
This would import a record for Sarah with three attributes - ID, NAME and PHONE, the last of which will have three values. A fixed width file would work the same way.
- While the DSML specifications themselves can actually handle attribute level updates using the addRequest, delRequest and modifyRequest operations, FIM only implements the ability to import a SearchResultEntry element which must contain all of the attributes on the object
Just a side note for those that might be curious, you can actually place the addRequest, delRequest and modifyRequest nodes in the DSML file. FIM will be able to parse the file and it wont cause any errors, however these elements are completely ignored and aren’t processed by FIM. I also tried sending a DSML delta to FIM with just the attribute that changed and a change type of “modify”, and I suppose not surprisingly, the object in the connector space was updated so that it only had the one attribute I specified, all the other attributes originally on the object were removed. Had any of these attributes been defined as required, this update would have failed.
- While you can import an update to a specific value in a multi-valued attribute, if you were to export this same change to an LDIF file, it will come through as a replace operation containing all values now present on the attribute
- While the SQL MA does not support updates to a specific value on a multi-valued attribute out of the box, I hear rumor that some customizations can be done to make this happen
Thursday, July 30, 2009
.NET Google SSO Part 2 of 2
This is the second in a series of articles discussing the implementation of an SSO application for Google Apps. The first .NET Google SSO Part 1 of 2 began the discussion by laying out the steps needed to handle the initial Authentication Request made by Google. This final piece will complete the package by illustrating the generation of the Authentication Response.
Google will expect the Authentication Response to come back as a form posted to the AssertionConsumerServiceURL provided by Google in the inital request. The form needs to have at least two elements on it, a <textarea> named SAMLResponse and an <input> named RelayState. The RelayState element is the url to redirect the user to at Google once the response has been sent. This is usually the same as the RelayState that Google provided to you via the RelayState url parameter.
Building the SAMLResponse is a little bit more involved. The SAMLResponse will contain the xml body of the AuthnResponse, which has the following format:
<?xml version="1.0" encoding="UTF-8"?> |
Where the items in red will need to be replaced with actual values before sending the response to Google. Here are some specs for those items:
Attribute | Description | Examples |
ASSERTION_ID | A 160-bit string made up of randomly generated lower case alpha characters from a through p | dfpccklacbmnmioodokleambcplpmfghahihdmna |
ISSUE_INSTANT | Should be the current date and time in the format: | 2000-01-01T23:01:01Z |
AUTHN_INSTANT | Should be the current date and time in the format: | 2000-01-01T23:01:01Z |
NOT_BEFORE | This defines the beginning timeframe for which the authentication is valid. Should be the current date and time in the format: | 2000-01-01T23:01:01Z |
NOT_ON_OR_AFTER | This defines the ending timeframe for which the authentication is valid. Should be the current date and time in the format: | 2000-01-01T23:01:01Z |
ACS_URL | The URL to send the authentication result | https://www.google.com/a/yourCompany.com/acs |
USERNAME_STRING | The username of the person validated | jsmith |
DIGEST_VALUE | The value of the digest of the Reference URI calculated using the algorithm listed in the DigestMethod | Qo9gKjwBgNtt6P07aIZmIPXP+uQ= |
SIGNATURE_VALUE | The value of the digest of the SignedInfo Element calculated using the algorithm listed in the SignatureMethod | 55khyrdDp0SgPmlu5dH49CAfASW2psDLhgjaB+Yl06pfxLJWnIctb7pX0K3k/vhNU8sUMY6Ps582CS6+YUPJps45U0i |
RSA_KEY_MODULUS | For use in the RSA encryption algorithm | K88ntfSyp1JU9Nu1KJwk+KKOuunT9G1RLwJXm6WrDb2klVGXLNKcP72lu5AlyGgYoZXO2bY2d610LE7kGol3Hu |
RSA_KEY_EXPONENT | For use in the RSA encryption algorithm | AQAB |
Here are the basic steps we need to take to create the AuthnResponse:
- Authenticate the user
- Generate an xmlDocument object using the AuthnResponse Template
- Fill in the AuthnResponse parameters
- Create a new signedXml object based on the xmlDocument
- Submit an html form with the InnerXml of the signedXml object and the RelayState
If we continue with the project created using the first blog post, we currently have one item on our form, a label called lblError. You will need to add two text boxes, txtUser and txtPwd to allow the user to enter their credentials and a button, btnSubmit. Format the form to your liking, and then add some code to authenticate the user, this can be done against a directory, a database, etc. This example will authenticate a user against ADAM.
// Class level vars |
Now that our user is authenticated and we have their Google UserName, the next step is to generate an xmlDocument object using the AuthnResponse template. The template that we need is similar to the AuthnResponse shown above, with one very important difference; we don't want the <Signature> element or its children. We will be adding this using the signedXml object later. Create an xml file named AuthnResponseTemplate in your project directory. Copy in the AuthnResponse xml below and save the document.
<?xml version="1.0" encoding="UTF-8"?> |
We will now add code to consume this new file and replace the elements in red with proper values:
///<summary> |
Next, we will be adding the xml signature. Be sure to update the file path to the x509 cert used for signing the xml. This certificate must contain the private key:
///<summary> |
Finally, we will bring it all together in the submit button on_click event handler and generate the html form with the SAMLResponse and RelayState and send it on to Google:
///<summary> |
That should do it! The user will then be allowed into their Google account.
Friday, March 27, 2009
.NET Google SSO Part 1 of 2
Creating an SSO for Google can be a bit of a challenge. There are quite a few good examples for doing this in Java, but not as many for .NET. Here is my attempt to resolve that issue. This article will be broken up into two parts, the first of these is handling the authentication request from Google, the second of these will illustrate the response generation.
Let's start by getting a good overview of the design. The entire process will begin when the end-user tries to access their Google Account. If the Google Apps service has been configured to use SSO, Google will generate an Authentication Request and send it on for you to handle in your SSO. It is then up to you to perform user authentication and generate a signed Authentication Response to send back to Google.
Okay, now the details. When you receive an AuthenticationRequest from Google, it will make an http request to the URL you have specified in your Google Apps account with two additional query string parameters: SAMLRequest and RelayState. The SAMLRequest will look like a series of random letters and numbers that is in actuality a base64 encoded string containing the AuthnRequest. RelayState is the RFC 1783 encoded URL that the user is ultimately trying to get to, in this case probably their Google email account. So this would look something like:
http://www.yourCompany.com/pathToPage/yourSSOPage.aspx?SAMLRequest=eJxdkN1uwjAMRl8lyn1%2f6NCEIgpim7YhsQlB2cXuQuK2KW2cxSni8Sk%2fk6bd2v7s4zOdn7qWHcGTQZvzUZxyBlahNrbK%2ba54jSZ8PpuS7FonFn2o7QZ%2beqDAhpwlcW3kvPdWoCRDwsoOSAQltouPlcjiVDiPARW2nC1fcl6rpqnLWtkDqIPU7tA4BftS1pVrGq1LpVF1pQbOvn6hsgvUkqiHpaUgbRhKaTqJRmmUTYrRo3jIxHj8zdn6funJ2Bv%2fP6z4L9b%2bNkTivSjW0Qa08aDCdcnRaPCfQyLnFWLVQqyw42xBBD4MSM9oqe%2fAb8EfjYLdZjX8FYITSdKikm2NFJK3a7IYVCUXb3dtsSR34iyZnQGwVYL1&RelayState=http%3a%2f%2fmail.google.com%2fa%2fyourCompany.com
Before we go much further, let's talk about the AuthnRequest. The AuthnRequest is an XML document that has the following format:
<?xml version="1.0" encoding="UTF-8" ?> |
Where the items in red will be replace with actual values by Google at the time of generation. Here are some specs for those items:
Attribute | Description | Examples | |
AUTHN_ID | A 160-bit string made up of randomly generated lower case alpha characters from a through p | dfpccklacbmnmioodokleambcplpmfghahihdmna | |
ISSUE_INSTANT | Should be the current date and time in the format: | 2000-01-01T23:01:01Z | |
PROVIDER_NAME | This is the domain name of the calling application | google.com | |
ACS_URL | The URL to send the authentication result to | https://www.google.com/a/yourCompany.com/acs | |
Your first task will be determining the values of the two query parameters mentioned above and decoding them. In order to perform some of the decoding you will need to use a compression utility, I use a nice open source one available from ic#code at http://www.icsharpcode.net/OpenSource/SharpZipLib/.
So let's begin! Start a new web project and then make sure you add the following references: ICSharpCode.SharpZipLib and System.Security. Edit the default.aspx page, adding the following using statements…
using System; |
Next, are the basic steps we need to take to decode the AuthnRequest:
- Retrieve data from the query string
- Decode the base64 string to a byte array
- Decompress (inflate) the array
- UTF8 Encode the array back into a string
So here's what the code looks like to do all of that, however, you will first need to add a label to your form called lblError to communicate any issues back to the user:
///<summary> |
This code can be called from the Page_Load method to validate the request before prompting the user for their credentials. Be sure to check the Page.IsPostBack property to only call decodeAuthnRequestXML function on the initial page load.
// Class level vars |
The string you get back from the decodeAuthnRequestXML function should be user readable XML with the AuthnRequest format mentioned above. It should look something like:
<?xml version="1.0" encoding="UTF-8" ?> |
Once you have that, you can parse the XMLDocument and begin building your response. Look for Part 2 of the SSO series to demonstrate the building of the AuthnResponse.

