Category Archives: SSO

Building a custom Single Sign-On module for JAVA web apps

The last few weeks I’ve been working on a project that involved Single Sign-On using JAVA web applications. The main purpose of the project was to create a smooth, simple and configurable library that provides SSO to existing JAVA web apps and integrates as easy as possible. In this post I’ll share useful links that provide you all the information you need to embark in a similar journey and some tips that will help you through the way. Along with these, you will find some code that can be used for specific features you have to implement.

To develop and test the library I used the following platforms, environment and technologies. The developing tool was Eclipse [kepler] on a Windows System, and the server selected to host the apps was Tomcat7. Of course you’ll need a JAVA SDK and a STS (in this case was an ADFS 2.0) to provide the security tokens for authentication. So most of the advice within the article will be related to ADFS.

First of all if you’re new to this world, you can start reading about the protocols commonly involved like WS-FED, SAML1 and SAML2. Below you have a list of links that can be used as starting points for each one of these technologies, providing an overall idea of each one and you can use, following the links within them, to get deeper understanding of what is happening under the hood (as you might be implementing authentication requests, logouts, etc):

The next step is to get a library that provides most of the required functionality and pieces you need to build your own solution over it. I found OpenSAML for JAVA one of the best choices for this (http://shibboleth.net/products/opensaml-java.html). As the library description says it does not provide a full implementation of any of the high level entities as Identity Providers, Service Providers, and/or Advanced Clients which is the focus of this article as we will be talking about clients performing SSO.

Integration and SSO features support on the client side can be achieved by implementing a JAVA filter interface (javax.servlet.Filter) that will intercept requests and inspect whether an user is already authenticated within the service provider, or a token is being posted by the STS as a result of an authentication request done before in behalf of the SP.

From this fact you can deduce that you will need custom logic for three main things:

  • Maintain the credentials of an already authenticated user – more likely by implementing a Principal interface (java.security.Principal)
  • Write custom code to validate a posted token in order to authenticate the user and create the Principal instance (this is where you could rely on the OpenSAML library)
  • Initiate new authentication requests automatically using a custom configured STS (that can be done by just a couple of helper classes)

I will not get into details of how to implement the Principal interface or how to handle the Principal instance after a posted token has successfully been validated, but it is trivial that you will store the list of received claims along with the Principal instance and you will handle and keep this object alive as long as required (within a session, cookie or another persistence mechanism allowing some kind of TTL/expiration).

You could have something like shown below:

[sourcecode language=”java”]
public class ClaimsPrincipal implements Principal, Serializable {
private static final long serialVersionUID = 6348413065734100547L;

protected List<Claim> claims = null;
.
.
.
public List<Claim> getClaims() {
return Collections.unmodifiableList(this.claims);
}
}
[/sourcecode]

And for the logic required to validate the posted token and obtain the claims you can create a TokenValidator class (or whatever) that will rely on the functionality provided by the OpenSAML library. This class can have a unique public method called something like validate() which will return the list of claims that you might need to create the Principal instance signaling an authenticated state. This is the most complex task to do and I will not get into details, but you can find useful resources and samples using the OpenSAML library for JAVA on the web.

This the idea of authenticating and managing an user can be summarized with the following pseudo-code:

[sourcecode language=”java”]
TokenValidator validator = new TokenValidator();
try {
List<Claim> claims = validator.validate(postedToken);
PrincipalStore.store(new ClaimsPrincipal(claims));
}
catch (Exception ex) {
[do something with the exception – ex log]
}
[/sourcecode]

And then you can query the Principal Store to check whether an user is already authenticated when receiving new requests or not:

[sourcecode language=”java”]
boolean isAuthenticated = PrincipalStore.retrieve() instanceof ClaimsPrincipal;
[/sourcecode]

But.. What is the user is not already authenticated? We can handle this situation and redirect the request to the STS to start an authentication process. You can do this using WS-FED or SAML2 protocols. The query string required to perform a WS-FED auth request is pretty simple and you can find many examples on the web, and for the SAML2 protocol the easiest way is to implement a HTTP Redirect Binding (http://en.wikipedia.org/wiki/SAML_2.0#HTTP_Redirect_Binding).

As the payload for this can be a little tricky when dealing with ADFS, below is the template that I successfully used against our ADFS. You can use it as well to build a SAML2 auth request to ADFS:

[sourcecode language=”xml”]
<samlp:AuthnRequest
ID="_85e10b08-0f76-4491-be86-07324727c4ed"
Version="2.0"
IssueInstant="2013-08-16T17:12:49.719Z"
Destination="https://[ADFS-URI]/adfs/ls/"
Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
http://[ADFS-URI]/adfs/services/trust
</Issuer>
<Conditions xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<AudienceRestriction>
<Audience>
[service-provider-urn]
</Audience>
</AudienceRestriction>
</Conditions>
</samlp:AuthnRequest>
[/sourcecode]

As said, with this you can create a valid SAML2 auth request that will be gracefully accepted by ADFS to start a login and post a token back to your service provider. In addition, and as the ADFS can be configured to require signed auth requests, you might need to add signature parameters to your query string (signature algorithm and signature digest). In that case you will need to get a private key from a certificate store in order to perform a rsa-sha1 sign for example.

Here you can see how the code to extract a private key from a keystore could look like:

[sourcecode language=”java”]
public static PrivateKey getPrivateKey(InputStream keyStoreStream, String alias, String password)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(keyStoreStream, password.toCharArray());

KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(alias,
(KeyStore.ProtectionParameter) new KeyStore.PasswordProtection(password.toCharArray()));
PrivateKey pk = pkEntry.getPrivateKey();

return pk;
}
[/sourcecode]

I hope this article has been useful to you, and help you a little in the process of implementing a custom SSO module within your JAVA web app. If you have design/implementation questions you can write me for further details 🙂

Load Testing ADFS-Federated SharePoint Applications

If you create a Visual Studio Load Test for a SharePoint application that uses Federated Authentication using ADFS (Active Directory Federation Services), you might end in a situation where each Web tests request of the Load Test does not arrive to the application, but is stuck in an ADFS redirection like this:

image

Without getting into the technical details, the error message you see (‘Script is disabled. Click submit to continue’), is because the Visual Studio Test Engine does not support JavaScript and thus the automatic POST of the SAML token into the Relying Party (i.e. your application) does not work (more details here).

In these cases, before actually being able to perform a successful request that hits your SharePoint application, you will need to perform an explicit authentication request to ADFS to get a valid Authentication cookie (AKA FedAuth cookie) and send this cookie in all subsequent requests. This will make the request an ‘authenticated request’, avoiding the redirection to ADFS and thus the error above. Throughout this post you will learn how to implement this flow within a Load Test by creating a Login Web Test that authenticates Virtual Users in ADFS.

Disclaimer: To keep things as short as possible I won’t get in Visual Studio Load Testing or ADFS details. I will assume that you’ve used VS Testing platform before and you are somehow familiar with ADFS. If you want VS Load Testing documentation this post has a comprehensive set of links. Additionally, I’ve also found this Visual Studio Performance Testing Quick Reference Guide a gem; it is a bit more advanced, but very complete, covering lots of specific cases. Finally, notice that I will  assume some ADFS and SharePoint configurations, but I’ll try to make them explicit.

1. To start I’d suggest that you use Fiddler to inspect a normal authentication flow in your SharePoint application. Assuming ADFS is configured for Windows Integrated Authentication, you should get a set of redirections, be prompted for your username/password, and arrive to your target application with a valid FedAuth cookie. Check the last request to ADFS and take note of the wa (the operation name), wrealm (your application identifier) and wctx (in this case the app return URL after ADFS sign in) querystring values. Make sure you copy the values as they are, including the URL encoding.

auth-flow-fiddler

2. Now let’s switch to Visual Studio. On a new Web Test, let’s add a new request to the ADFS Integrated Login URL (…/adfs/ls/auth/integrated) passing the wa, wtrealm and wctx values you’ve obtained as QueryString Parameters. Then add three Form Field extraction rules for the following values: wa, wctx, wresult. Make sure the corresponding Context Parameters are created in the Web test.

adfs-request

This will perform a Windows Integrated authentication request simulating part of a normal federated authentication flow. After Visual Studio provides valid AD credentials (configured in the Web Test properties as shown below), ADFS will return a valid SAML Token in the wresult form field of the response. With the Extraction Rules, Visual Studio will extract the SAML Token value and place it the wresult Context Parameter for using it in the next request you will create (wa and wresult will also be extracted and re-sent).

3. Now you need to add another request to the Web Test for posting the SAML token to the SharePoint application. To do this, you should create a request to the Sharepoint STS URL (/_trust/) under your SharePoint application, passing the wa, wctx and wresult context parameters (the {{…}} pattern indicates the use of context parameters values). The response of this request will have a valid FedAuth cookie, which will be automatically stored by Visual Studio in a cookie container and sent back on subsequent requests to the application under test.

4. It’s also a good idea to add a final request to the application under test to make sure authentication worked as expected. Ideally, a Validation Rule should be added to ensure that the request is indeed reaching the application and not bouncing back to ADFS for authentication. For example, you can add a validation rule that parses some user identifier value present in the page.

5. Let’s now run the Web Test stand-alone to make sure it’s working as expected.

successful-test

6. Good, you now have a Visual Studio Web Test that performs login with ADFS and gets back a valid FedAuth cookie. So let’s see how this can be used within a Load Test. When creating a Test Mix you can specify an Initialize test, which is run by each Virtual User before any of the tests in the Test Mix are executed. This way each Virtual User will first login in ADFS and get a valid FedAuth cookie before executing other Web Test to add load to your application. All subsequent load test requests performed will hit your application directly, without redirecting to ADFS and thus seeing the error from the beginning of this post.

Please notice that if the testing time exceeds the validity period of the FedAuth cookie all the Web Tests of your Load Test will start to fail. The expiration time of the FedAuth cookie in SharePoint is set to 10 hours by default, but in your environment this might differ – check this thread with more information on how to check it.

Thanks to Rodrigo Molinas (@romolinas) and Sebastian Ballarati (@sballarati) for their contribution in the code for this post.

ADFS: Transforming Claims using Regular Expressions

In ADFS v2.0 you can use regular expression (regex) in the claim rules to either:

  • Check for a condition in an incoming claim
  • Transform claim values

In this post I’ll show you how to perform both with a simple example. Now, let’s say that I have an incoming claim that says a user can access Document C within Collection B, which is under Site A:

‘MyClaim.SiteA.CollectionB.DocumentC.Access’

In this case I want to issue a claim that states that this user can also access everything under Site A:

‘MyClaim.SiteA.Access’

One interesting thing about the ADFS Claim Rule Language is that it also supports the regexreplace() method, to perform custom transformation of claim rules values using regular expressions. In this case, you can use the regexreplace() method to extract the Site A value from the incoming claim and send it in the transformed claim, as follows:

  1. In the claim condition look for a claim value that matches the incoming claim format:

    c:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/role“,
    Value =~ “^(?i)MyClaim.([^.]+).([^.]+).([^.]+).Site$”]

    Some comments from the condition above:
    – The three ([^.]+) patterns are used to match claims with the format {value}.{value}.{value}
    – The =~ operator in the claim rule Value field specifies to use regular expressions for checking the condition
    – The (?i) pattern in the condition is used to ignore casing
    – The ^ and $ characters mark the beginning and the end of the claim value. In short, are there to make sure that the claim starts with MyClaim… and ends with …Site

  2. The in the Issue expression use the regexreplace() method:

    issue(Type = “http://schemas.microsoft.com/ws/2008/06/identity/claims/role“,
    Value = regexreplace(c.Value, “^(?i)MyClaim.(?<site>[^.]+)..+”, “MyClaim.${site}.Access”));

    The important things to notice above are:
    –  The (?<site>[^.]+) pattern will search for the site value in the incoming claim and store it in the site parameter (the ?<…> pattern is used for naming parameters).
    – The ${site} pattern in the transformed claim will be replaced by the value extracted from the incoming claim

Summarizing, the complete Claim Rule would be as follows:

c:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/role“, Value =~ “^(?i)MyClaim.([^.]+).([^.]+).([^.]+).Site$”] => issue(Type = “http://schemas.microsoft.com/ws/2008/06/identity/claims/role“, Value = regexreplace(c.Value, “^(?i)MyClaim.(?<site>[^.]+)..+”, “MyClaim.${site}.Access”));

For more information on ADFS Claim Rule Language see this article: Understanding Claim Rule Language in AD FS 2.0

Hope you find it useful.

Windows Azure AppFabric Access Control in Practice (Spanish)

Como habia escrito en un post anterior, aqui dejo un video donde muestro Windows Identity Foundation y Windows Azure Access Control Service.

En este ejemplo muestro lo siguiente:

  • Creo un sitio web de cero y agrego un identity provider de prueba (Add STS Reference)
  • Me falla una cosa con certificados y hago un poco de troubleshooting
  • Configuro el mismo sitio en Windows Azure Access Control (ACS) y genero la relacion de confianza entre mi sitio y ACS
  • Configuro otros identity providers en ACS
  • Muestro como podemos logearnos a una aplicacion utilizando diferentes proveedores de identidad. En particular muestro el ADFS de Microsoft,  el ADFS de Southworks, Google, LiveID, etc.

Sobre el final contesto algunas preguntas…

image

Espero que les sea util!

Troubleshooting WS-Federation and SAML2 Protocol

imageDuring the last couple of years we have helped companies deploying federated identity solutions using WS-Fed and SAML2 protocols with products like ADFS, SiteMinder in various platforms. Claims-based identity has many benefits but as every solution it has its downsides. One of them is the additional complexity to troubleshoot issues if something goes wrong, especially when things are distributed and in production. Since the authentication is outsourced and it is not part of the application logic anymore you need someway to see what is happening behind the scenes.

I’ve used Fiddler and HttpHook in the past to see what’s going on in the wire. These are great tools but they are developer-oriented. If the user who is having issues to login to an app is not a developer, then things get more difficult.

  • Either you have some kind of server side log with all the tokens that have been issued and a nice way to query those by user
  • Or you have some kind of tool that the user can run and intercept the token

Fred, one of the guys working on my team, had the idea couple of months ago to implement the latter. So we coded together the first version (very rough) of the token debugger. The code is really simple, we are embedding a WebBrowser control in a Winforms app and inspecting the content on the Navigating event. If we detect a token being posted we show that.

Let’s see how it works. First you enter the url of your app, in this case we are using wolof (the tool we use for the backlog) that is a Ruby app speaking WS-Fed protocol. .

image

After clicking the Southworks logo and entering my Active Directory account credentials, ADFS returns the token and it is POSTed to the app. In that moment, we intercept it and show it.

image

You can do two things with the token: send it via email (to someone that can read it Smile) or continue with the usual flow. If there is another STS in the way it will also show a second token.

image

image

Since I wanted to have this app handy I enabled ClickOnce deployment and deployed it to AppHarbor (which works really well btw)

If you want to use it browse to and launch the ClickOnce app @ http://miller.apphb.com/

If you want to download the source code or contribute @ https://github.com/federicoboerr/token-requestor

Consumer Identities for Business transactions

A year ago I wrote a blog post about how to use the Windows Identity Foundation with OpenID. Essentially the idea was writing an STS that can speak both protocol WS-Federation and OpenID, so your apps can keep using WIF as the claims framework, no matter what your Identity Provider is. WS-Fed == enterprise, OpenID == consumer…

Fast forward to May this year, I’m happy to disclose the proof of concept we did with the Microsoft Federated Identity Interop group (represented by Mike Jones), Medtronic and PayPal. The official post from the Interoperability blog includes a video about it and Mike also did a great write up. I like how Kim Cameron summarized the challenges and lessons learnt of this PoC:

The change agent is the power of claims.  The mashup Mike describes crosses boundaries in many dimensions at once:

  • between industries (medical, financial, technical)
  • between organizations (Medtronic, PayPal, Southworks, Microsoft)
  • between protocols (OpenID and SAML)
  • between computing platforms (Windows and Linux)
  • between software products (Windows Identity Foundation, DotNetOpenAuth, SimpleSAMLphp)
  • between identity requirements (ranging from strong identity verification to anonymous comment)

The business scenario brought by Medtronic is around an insulin pump trial. In order to register to this trial, users would login with PayPal, which represents a trusted authority for authentication and attributes like shipping address and age for them. Below are some screenshots of the actual proof of concept:

image

image

image

image

While there are different ways to solve a scenario like this, we chose to create an intermediary Security Token Service that understands the OpenID protocol (used by PayPal), WS-Federation protocol and SAML 1.1 tokens (used by Medtronic apps). This intermediary STS enables SSO between the web applications, avoiding re-authentication with the original identity provider (PayPal).

Also, we had to integrate with a PHP web application and we chose the simpleSAMLphp library. We had to adjust here and there to make it compatible with ADFS/WIF implementation of the standards. No big changes though.

We decided together with the Microsoft Federated Identity Interop team to make the implementation of this STS available under open source using the Microsoft Public License.

And not only that but also we went a step further and added a multi-protocol capability to this claims provider. This is, it’s extensible to support not only OpenID but also OAuth and even a proprietary authentication method like Windows Live.

image

DISCLAIMER: This code is provided as-is under the Ms-PL license. It has not been tested in production environments and it has not gone through threats and countermeasures analysis. Use it at your own risk.

Project Home page
http://github.com/southworks/protocol-bridge-claims-provider

Download
http://github.com/southworks/protocol-bridge-claims-provider/downloads

Docs
http://southworks.github.com/protocol-bridge-claims-provider

If you are interested and would like to contribute, ping us through the github page, twitter @woloski or email matias at southworks dot net

This endeavor could not have been possible without the professionalism of my colleagues: Juan Pablo Garcia who was the main developer behind this project, Tim Osborn for his support and focus on the customer, Johnny Halife who helped shaping out the demo in the early stages in HTML :), and Sebastian Iacomuzzi that helped us with the packaging. Finally, Madhu Lakshmikanthan who was key in the project management to align stakeholders and Mike who was crucial in making all this happen.

Happy federation!

Sharepoint 2010 and ADFS

I’ve seen a few questions on identity federation with SharePoint before, so I thought about sharing this more broadly.
I recorded a 9 minutes screencast showing the capabilities of ADFSv2 + SharePoint 2010. This is using Microsoft STS, LiveID and our own company STS allowing the following usecases:

  • Manage access to employees that belong to the Active Directory
  • Manage access to partners that has their own STS
  • Manage access to certain webparts, doc libraries or lists through Sharepoint groups and claims
  • Allow/deny access to Windows LiveID users

image

Claims-based Identity and Access Control Guide RTM!

I found myself posting more on twitter than my blog. However this deserved a post.
The RTM of the guide is finally out there in PDF version.

image

Looking at my name in the cover of a book together with such a group of experts is really a significant milestone in my career. I want to specially thanks Eugenio for trusting me and inviting me to participate in this project. Hope you find the content useful. If you have any questions or you want to discuss about claims, identity, federation towards your next project feel free to mail me at matias at southworks dot net.

Now heading towards the second book: Cloud Guidance! Stay tuned…

Claims based Authentication & Authorization: The Guide

Eugenio announced yesterday the kickoff of a new guide from patterns & practices in which I’m collaborating: Claims based Authentication & Authorization Guide.

This is not a new topic as Eugenio suggests in his blog, but it’s getting more and more attention because:

  • Technology is more mature, hence it’s easier to implement claim-based identity
  • Enterprises are failing to control the amount of different identity repositories, leading to higher provisioning/deprovisioning costs, security problems, etc.
  • End users want simpler user experiences and less passwords
  • The cloud makes all these even more challenging

We started with this project a couple of weeks ago planning the content. The approach we decided to use was heavily driven by scenarios (aka zero bulls**t). We used the visual metaphor of a tube map with scenarios being the stations separated in two main lines:

  • The blue one, the Enterprise track approaches the federated identity problem from the point of view of a company with many applications that wants to implement SSO and Federation. The main stations are SSO (within the enterprise), Federation (with partners), SOAP Web Services (and flow of identity across services), SSO with a third party cloud app and some variations like: what if the company decides to host an application on the cloud (namely Windows Azure); or what if the company needs to integrate with an application that talks SAML protocol (i.e. Salesforce, Google Apps)
  • The yellow one, ISV track on the other hand tackle the problem from the perspective of an ISV that wants to offer an application as a service (think about Salesforce or Dynamics CRM Online as the canonical examples). In this track we start by explaining how to implement federated identity for a cloud application. Then we show how to automate federation to on board new customers. We also show things like exposing a REST API and how that plays with claims; how to integrate with LiveID (or OpenID) for small customers that don’t have an Identity Provider in place; and we end up explaining how to do auditing/billing with claims.

image

I’m very proud and excited about being part of such a great team including: Dominick Baier, Vittorio Bertocci, Keith Brown, David Hill and Eugenio Pace. I’m sure that something great will come up from this team, the board of reviewers and the community that will help to prioritize and keep the focus!

Getting a token from ADFS (ex Geneva Server) using WCF

I’ve been doing some tests to get a token from ADFS (Geneva Server) using Windows Identity Foundation  WSTrustClient. In this case we are using the UserNameMixed endpoint that expects a WS-Security UsernameToken (notice the MessageCredentialType.UserName).

internal static ClaimsIdentityCollection RequestTokenWithUsernameMixed()
{
    var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
    binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
    binding.Security.Message.EstablishSecurityContext = false;

    var credentials = new ClientCredentials();
    credentials.UserName.UserName = "Mary";
    credentials.UserName.Password = "Passw0rd!";
    var endpoint = "https://mygenevaserver/Trust/13/UsernameMixed";
    var client = new WSTrustClient(binding, new EndpointAddress(new Uri(endpoint)), TrustVersion.WSTrust13, credentials);

    var request = new RequestSecurityToken();
    request.RequestType = "http://schemas.microsoft.com/idfx/requesttype/issue";
    request.AppliesTo = new EndpointAddress("http://localhost/activerp");
    var token = client.Issue(request) as GenericXmlSecurityToken;

    var claims = token.ToClaimsIdentityCollection(TrustVersion.WSTrust13, 
CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine,
"CN=Geneva Signing Certificate - WIN-66EYOLL2BVY"),
CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine,
"CN=WMSvc-WIN-66EYOLL2BVY")); return claims; }

Here is another one using the WindowsMixed endpoint (notice the MessageCredentialType.Windows and no username and password set)

internal static ClaimsIdentityCollection RequestTokenWithWindowsMixed()
{
    var binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
    binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
    binding.Security.Message.EstablishSecurityContext = false;

    var credentials = new ClientCredentials();
    var endpoint = "https://mygenevaser/Trust/13/WindowsMixed";
    var client = new WSTrustClient(binding, new EndpointAddress(new Uri(endpoint)), TrustVersion.WSTrust13, credentials);

    var request = new RequestSecurityToken();
    request.RequestType = "http://schemas.microsoft.com/idfx/requesttype/issue";
    request.AppliesTo = new EndpointAddress("http://localhost/activerp");
    var token = client.Issue(request) as GenericXmlSecurityToken;

    var claims = token.ToClaimsIdentityCollection(TrustVersion.WSTrust13, 
CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine,
"CN=Geneva Signing Certificate - WIN-66EYOLL2BVY"),
CertificateUtility.GetCertificate(StoreName.My, StoreLocation.LocalMachine,
"CN=WMSvc-WIN-66EYOLL2BVY")); return claims; }

You can use this together with the CreateChannelWithIssuedToken extension method (as shown in a previous post).

Download the code