CardSpace and SharePoint – Part II
In the Rabbit Hole, Keep Your Head Above Water!
In a previous post where we were discussing CardSpace and SharePoint, there was dialogue of some of the basics of Windows CardSpace and how it can possibly interact with SharePoint as a possible type of authentication mechanism (term used in a loose sense). In that post, I was attempting to introduce you at a high level the operations of CardSpace, and how, at a high level, it plays an important role in building an interactive piece (always remember, CardSpace is a piece of this!) of an identity metasystem, easily one of the most exciting security concepts to consider in the realm of current collaboration security technology. We talked about some interesting security concepts, which hopefully wet your appetite a little more to the proposal of integrating CardSpace and SharePoint into a cohesive solution that exploits the benefits of each of these assets to their maximum potential, while integrating their unique attributes into a singular system.
In this post, I will delve a little more in depth into the concepts behind CardSpace, and we will begin to see some of the more granular innards of how CardSpace functions. As well, in this discussion you will begin to understand how the CardSpace controls for SharePoint work and how using CardSpace enabled features can play the role of an authentication mechanism, as the basics of how the identity selector is instantiated from SharePoint will become clearer. This will give you a clearer understanding of what is happening under the hood with this whole hybrid CardSpace / SharePoint environment stuff.
Before we get started, working with the associated OM assets (System.IdentityModel.Claims, etc.) that is required when building solutions that tap into CardSpace is not big deal and nothing to shy away from. For example, iterating is iterating, like iterating through CardSpace claims is a relatively straightforward process since each type of ClaimType objects can be called through a ClaimTypesCollection.
- //quasi-pseudo code for ClaimType iteration
- foreach (ClaimType claims in ClaimTypesCollection)
- // Do Something
As we saw in the previous post, adding CardSpace support to SharePoint is not an exceptionally difficult task, as the steps to adding CardSpace support for normal ASP.NET 2.0 web applications (for which SharePoint architecturally belongs to) is not technically convoluted. Initially, it may appear that CardSpace solely functions by adding an HTML OBJECT tag which plays the pivotal role in calling the CardSpace identity selector (however it should be noted that it is possible to use XHTML). However, there are couple things that happen during this process though that deserves some attention. Firstly, we have the OBJECT tag that CardSpace requires, which we will examine a little more closely in a minute. Secondly, the form must be submitted, which will invoke the identity selector; this is essentially calling the object. The CardSpace server code (controls) massage the encrypted token in order to compute the claims as appropriate by pooling and decrypting the token according the private key of the SSL certificate. Then the encrypted (note that this token is encrypted with WS-Security), signed XML token can be sent to SharePoint. There are some more minor processes that occur, but this is a good high level overview regardless.
There are a bunch of Identity Selector parameters, however I am just going to go over the ones that I think are important. Ones that I don’t really want to type about right now (like issuerPolicy and privacyUrl) I will discuss in a separate post. Each of these parameters is important however whne architecting your CardSpace implementation because they will be used for the WS-SecurityPolicy data.
The information that is contained in the object tag is pretty self explanatory. The first portion of it is the object mimetype declaration. This is important to understand because working with cross-browser scenarios in relation to InfoCard support you will end up exploring InfoCard MIME Type existence testing to elegantly handle SharePoint users (simple comparisons on whether the user can leverage CardSpace environmentally pending)
- <!--<object type='application/x-informationcard' name='_selector'--> -->
This is just the beginning of the OBJECT declaration that is required in order to invoke the identity selector. We can see that the object tag is decorated with it’s MIME type, in this case it is for the InfoCard and the name attribute.
The second part of the OBJECT declaration is going to tell you the type of token that is being passed.
- <param value="urn:oasis:names:tc:SAML:1.0:assertion" name="tokenType" />
This is interesting, what is a SAML assertion? More along those lines, what is SAML? As SharePoint developers / architects, we don’t typically encounter SAML because the most of the time, it is typical to just use the default authentication / identity management schemes that are provided, and run with it. SAML stands for Security Assertion Markup Language, provided by the OASIS SSTC, and it provides methods that allow the exchange of relevant security information, namely identity and authentication information, building upon a widely understand standard, in this case XML. Because SAML is based on XML, it includes other technologies such as SOAP, HTTP, etc. XML is the most ideal data format to be used for the backend standard for SAML as it allows it directly available via a web browser, not requiring any type of client software. The main target of SAML is to reduce the overall cost and management that is associated with total user costs by providing a widely understand, easy to use standard that implements identity federation.
A SAML assertion can basically be thought of as a small container of information that is tiered around security data. There are two types of providers that exist in a SAML environment, an identity provider, as well as a service provider. Between these two, Assertions move from the identity provider to the service provider through a finite amount of paths. The purpose of both of the providers is pretty straight-forward. A SharePoint user will subscribe to an identity provider, this provider is responsible for authentication services. At this point, the assertion enters the argument. The assertion is generated by the identity provider. The generated assertion is passed to the service provider when the SharePoint user deems that it is appropriate. Then, as the service provider decides it, the user is granted access. This SAML assertion security data contains some very intriguing values. The first of these values is the header information. The header information will house some general data regarding the assertion, namely the identity provider formal name, expiration dates, etc.
There are some types of statements that are important to SAML in regards to CardSpace, authentication and attribute statements which are carried in the SAML assertion supplementing the header. The first of these, the authentication statement, will tell the service provider that the SharePoint at some point in time authenticated against the identity provider. The second of these, the attribute statements, simply contains metadata regarding the subject in name/value format that further define further details about the subject.
When working with these SAML attribute statements (these statements are essentially going to be represented as XmlElement objects out of System.Xml) you are going to need to check their validity, essential when coding against SAML, and easy to understand using some fairly standard XML functionality against the relevant XML nodes. You can see in the conditional test that we are building that we are using the IXmlElement interface as a parameter into our static condition. We are declaring this method as static because it is going to belong to the type itself rather than to a specific object. The IXmlElement interface because it helps to work with Xml objects. You can see that we are using the LocalName property because it will help to return the node’s qualified name and match it either against the string AuthenticationStatement or attribute statement (I am only showing one of each, but the strings values are the only things that would vary between the code statements).
- public static bool IsValid (IXmlElement xmlElement)
- if (! ((XmlElement) xmlElement).LocalName.Equals ("AuthenticationStatement"))
- return false;
- return ((XmlElement) xmlElement).NamespaceURI.Equals ("urn:oasis:names:tc:SAML:1.0:assertion");
You can use the IXmlElement in similar fashions when working with SAML. For example, you can use it when working with the pushing values to XML.
- IXmlElement xmlElement = ((XmlDocument) xmlDocument).CreateElement ("saml", "Attribute", "urn:oasis:names:tc:SAML:1.0:assertion");
When working with the X509certificates, you can also use the IXmlElement interface in order to get the certificate using two static methods that both take the IXmlElement as a parameter. We are going to be working with X.509 v.3 certificates (which actually isn’t encrypted itself, it is encoded in base64) because there has to be a mechanism in place that allows the user to verify that the SAML token was issued by trustworthy person, so it gets signed. For example, it would look like the following to get the relevant signature, which is required because the signature value is the encrypted digest value. This is what you will decrypt to verify the digest. Anyways, here is the method:
- public static IXmlElement GetSignature (IXmlElement xmlElement)
- return ((IXmlElement) ((XmlElement) xmlElement).SelectSingleNode ("*[local-name(.) = 'Signature' and namespace-uri(.) = 'http://www.w3.org/2000/09/xmldsig#']");
The second method will use the first method in order to get the certificate out of the XmlElement object.
- public static IXmlElement GetX509Certificate (IXmlElement xmlElement)
- IXmlElement oxmlElement = XmlSignature.GetSignature (xmlElement);
- if (oxmlElement != null)
- return ((IXmlElement) ((XmlElement) oxmlElement).SelectSingleNode ("//*[local-name(.) = 'X509Certificate' and namespace-uri(.) = 'http://www.w3.org/2000/09/xmldsig#']");
- return null;
There is another statement that exists, and that is the authorization decision statement. We are not going to talk about this too much, but the concept that it provides in the realm of SAML is nonetheless important to understand. The authorization decision statement basically just says what actions a user is permitted to have on certain, arbitrary objects. For example, let’s look at it in some code to get a better idea.
- string myDecision;
- if ((myDecision = text) != null)
- switch (myDecision)
- case "Permit":
- return Decision.Permit;
- case "Deny":
- return Decision.Deny;
- case "Indeterminate":
- return Decision.Indeterminate;
We can see that there is a simple Permit / Deny gate that is being set up in regards to a decision string passed into the loop. This should give you a better idea of how authorization decision statements function in SAML.
Anyyyyyways, I could go on with working with SAML, XML, and C# all day, so let’s get back to CardSpace. It will probably be the subject of a future post, so stay tuned.
The next value that exists in the OBJECT tag is the issuer (Man, did I deviate, are we still talking about CardSpace?).
- <param value="http://www.sharepointsecurity.com/issuer" name="issuer" />
We talked about issuers in a previous post. Within CardSpace, there are generally two types of issues that exist, ones that are self-issued, and ones that issued from external companies. As we talked about CardSpace will query the issuer of the identity to obtain a digitally signed, encrypted XML token. People will often refer to the issuer as the STS (Security Token Server). This value contained in this parameter is the URI of the issuing entity.
The next parameter are the claims that are required. This can vary heavily. We already talked about what claims are. These are simply the claims that are required. In order for an InfoCard to become selectable within the CardSpace UI, the user must meet the demands of all the required claims. Otherwise, the InfoCard is typically greyed out and not selectable for the SharePoint instance. This is decorated as a space-separated list of URIs.
- <param value="http://www.sharepointsecurity.com/requiredClaims" name="requiredClaims" />
The next element is the optionalClaims element, which simply contains the claims that are optional. They are claims that are not necessarily required in order to process the users identity card for access to the SharePoint instance. For example, myFavoriteBeer = Blue Moon, would generally be an optional claim.
- <param value="http://www.sharepointsecurity.com/optionalClaims" name="optionalClaims" />
Those are the only parameters that I want to talk about right now.
Now, let’s first talk about some of the requirements of CardSpace, and why they exist. The most obvious requirement that you will see when using CardSpace with SharePoint is that it requires the use of SSL (Secure Sockets Layer). This is because CardSpace requires at the very least read access to the SSL private key. Now, this doesn’t necessarily mean that your entire SharePoint instance has to be SSL enabled, however this is the most typical implementation. Rather, the only page that requires having SSL enabled is the page where the identity selector that is going to be invoked must be secured with SSL. This is for good reason, due to the type of information that is going to be transferred over the transport layer with CardSpace; you want to be aware of the identity power, such as information regarding the SSL certificate.
CardSpace at least needs read access to the private key, because when CardSpace is relaying the XML token, it is going to be encrypted on the client by the use of the SSL public key. In order for decryption to happen CardSpace requires read access to the private key so that it can actually process the claims that are included in the SSL encrypted XML token.
So when you are sending a card to your CardSpace enabled SharePoint site, what exactly is being sent? Right now, we are used in a typical FBA enabled or Windows based site on sending some basic stuff, just objects like a username and password, nothing real complex. CardSpace is a little different however. The most important unique value that CardSpace will generate is a concept called a PPID, which is the personal private identifier. The PPID is essentially is an ID identifies a specific card for a certain relying party. The PPID is similar to other things that are sent in the encrypted XML token (claims), in that it is a rather complex claim, complex in the sense that the numeric generated is rather lengthy. The PPID that you send to one CardSpace enabled SharePoint instance will not be the same as the PPID that you send to another CardSpace enabled SharePoint instance, rather, they will differ greatly because the numeric is generated as the identity provider as a parameter. This is because of how the PPID is generated in regards to CardSpace. The PPID is generated using the parameters of the relying party certificate and something which is unique about the card. This is a beneficial because it prevents replay attacks across multiple sites that have CardSpace enabled authentication, because the certificate is used for the generation of the PPID.
So what does the PPID have to do with user authentication? Well, how are we used to authenticating users to our SharePoint instance? We use a username and password, and any number of .NET 2.0 authentication providers, be it Windows, Forms, or Web Single-Sign On, which binds into the SharePoint security system. When a user first hits your SharePoint instance that is enabled with CardSpace it will follow the process described in this post. Ata more granular level however, when the token operations proceed, the PPID will be saved locally on the user. Therefore, when the user next visits your SharePoint instance, there will be a comparison of the PPID that is requested against the one in the database. If the comparison operator between the two returns true, then the user is authenticated to the SharePoint instance, without the need for any type of re-authentication. If the user does not having a matching PPID, then the operations continues in a fist-time visited SharePoint flow, which would essentially follow the diagram described in the previous post. It is important to realize that the PPID should always be called from an encrypted, signed XML token; it should be used in mixed environments since this could lead to the PPID possibly becoming exposed.
This is ultimately, this is a much better process when authenticating your user since it eliminates password fatigue, and negates the need from multiple logins to several places. The following quote is a great way to consider current password schemes:
We should all remember that a secret passed unencrypted via a public medium is no longer a secret it’s a fact waiting for someone else to learn it. Richard Turner, Product Manager for Microsoft’s Identity Platform Developer Marketing group
However, CardSpace is MORE than authentication; it is a verification of an IDENTITY. An Identity is more than just your username and password word. It is all sorts of metadata that is associated with you.
For example, imagine that sharepointsecurity.com was a MOSS instance to login I would need the following authentication attributes:
Username : Adam
Password : Password
But an identity contains more information than just this, it contains things like:
Name : Adam Buenz
Username : Adam
Location : Eglin Air Force Base, Fort Walton Beach, FL
Favorite Food: Tacos
Favorite Beer: Blue Moon
Favorite Time To Work : Midnight to 4:00 a.m.
Etc. etc. etc.
An identity can contain a lot of information!
Ok, that is enough for this post on CardSpace, SAML, and everything else that we talked about. How random was this content, oh well. Based on how far I got on this today, I am probably going to need a few more posts about it before this series is closed up. Arg, I enjoy coding more than I enjoy writing. Oh well, happy CardSpacing!