Sunday, June 23, 2013

Integrating JSF web application with Openam using Spring Saml Extension.

  Integrating JSF web application with Openam using Spring Saml Extension.
Or Single Sign on With JSF
Or Java Single Sign on
Or Integrate Single sign on Using Spring SAML Extension.
Or Integrating Spring SAML Extension with Openam  (or any SAML provider).
Or Spring and Open AM security
Or Single sign on in JSF or Single Sign on with JSF
Or Spring security with openam

As discussed in my earlier article we can have an different set ups
Case1: SP (Your Java Web app) <===> IDP Proxy   <=====>  (IDP1, IDP2.....)
or if you just have one IDP then obviously there is no point in using IDP proxy in which case you setup will be like
Case2: SP (Your Java Web app or Openam generated Fedlet)  <=====>  (IDP)

So depending on CASE1 or CASE2 you will generate Fedlet on IDP Proxy or IDP respectively.

So What is Fedlet ?
- Well Fedlet is small web based openam client that can  be generated once you install openam. This web application will have few jsps and will help you to test your openam setup and it has enough code to send SAML requests and receive SAML Responses

Now lets get in to details as how to plugin in your JSF webapp with Openam ?
1. Lets say you have JSF webapp with a simple page with following url
http://abc.com:8080/TST/landingPage.jsf

STEP1: Login to openam  (IDP Proxy if its CASE1  else IDP if its CASE2) and click on generate the Fedlet. When you generate the Fedlet choose your
  • Realm (You can use root "/" realm, but better use different realm. I used realm001)
  • Circle of Trust : Let say "Cot1"
  • Identityprovider:  (The url of your openam Identity provider will appear in drop down)
  • Fedlet Name :http://abc.com:8080/TST (Can be anything but I just use url)
  •  Fedlet destination url : http://abc.com:8080/TST
Once this is done you will see an Openam screen which shows where the fedlet.war is stored.

STEP2: Now in fedlet war there is a "conf" directory with 4 xmls
  •   sp.xml
  •   sp-extended.xml
  •   idp.xml
  •   idp-extended.xml
I have noticed that sp.xml that is generated by default in fedlet is missing signing and encryption public key.So I copied the public key for signing and encryption from idp.xml. Assuming the same keys that are used by openam will be used by your java web application as well.
i.e

Copy content from idp.xml starting from  to sp.xml.
 <KeyDescriptor use="signing">
……..
</KeyDescriptor>
<KeyDescriptor use="encryption">
…….
</KeyDescriptor>

STEP3: We can use the idp.xml that’s found in Fedlet/conf directory. This is the xml that will allow our JSF application to send SAML request to Openam.

STEP4:. We can use the sp.xml that’s found in the Fedlet/conf directory. This will have information for service provider (TST JSF application ).There are few changes we need to make here in order for the response url’s to be intercepted by Spring SAML extension filters.
e.g. I generated Fedlet for entity id http://abc.com:8080/TST and here is how the changes look in sp.xml.

Comment the following in sp.xml
FROM:
<!--   Default Fedlet generated Log out Urls.
<SingleLogoutService
       Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
       Location="http://abc.com:8080/TST/fedletSloRedirect"
       ResponseLocation="http://abc.com:8080/TST/fedletSloRedirect" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
       Location="http://abc.com:8080/TST/fedletSloPOST"
       ResponseLocation="http://abc.com:8080/TST/fedletSloPOST" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
       Location="http://abc.com:8080/TST/fedletSloSoap" />
-->

 Change the above Single logout service url’s to as shown below (Basically in every URL we added "/saml/SingleLogout/alias/realm001/sp" )  where realm001 is the realm and “/sp” is the service provider url we choose when we created openam.Be extra careful when replacing this url to have correct realm name.
In case you have used root realm then you can replace the below urls with /saml/SingleLogout/alias/sp

TO: (Within sp.xml)
 <SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://abc.com:8080/TST/saml/SingleLogout/alias/realm001/sp"
ResponseLocation="http://abc.com:8080/TST/saml/SingleLogout/alias/realm001/sp" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://abc.com:8080/TST/saml/SingleLogout/alias/realm001/sp"
ResponseLocation="http://abc.com:8080/TST/saml/SingleLogout/alias/realm001/sp" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
Location="http://abc.com:8080/TST/saml/SingleLogout/alias/realm001/sp" />
                       
STEP5:  Change AssertionConsumerService (ACS) URL’S in sp.xml
FROM:
<!-- Default Fedlet generated
<AssertionConsumerService isDefault="true"
      index="0" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      Location="http://abc.com:8080/TST/fedletapplication" />
<AssertionConsumerService index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://abc.com:8080/TST/fedletapplication" />
-->  
TO:
<AssertionConsumerService isDefault="true"
index="0" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://abc.com:8080/TST/saml/SSO/alias/realm001/sp" />
<AssertionConsumerService index="1"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://abc.com:8080/TST/saml/SSO/alias/realm001/sp" />

Here the realm I used for testing was "realm001" in case you have used root realm then your url will be  saml/SSO/alias/sp

STEP6:


Please comment the following name id formats in sp.xml and leave transient name id format.

<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>

<!-- We don't need this as we use  just transient
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</NameIDFormat>
 -->
 
STEP7: In case you want your requests signed and assertions signed in sp.xml set

AuthnRequestsSigned="true" WantAssertionsSigned="true"


I had authentication turned and use a sample cert. For testing you can use the test cert provided by openam . Never use this "test" cert in a production environment.

STEP8:  Edit the sp-extended.xml by fixing metalias to include realm name and also verify the following atttiburtes


These 3 tags will have values only if you have openam proxy. If you have just openam IDP and your SP is talking to IDP directly do no set values for these tags.

<Attribute name="enableIDPProxy">
                <Value>true</Value>
</Attribute>
<Attribute name="idpProxyCount">
                <Value>1</Value></Attribute>
<Attribute name="idpProxyList">
    <Value>http://idp.abc.com:8080/openam</Value> //Strangely you use the IDP url though the tag says proxy
</Attribute>


//Set the cert names for signing and encryption.
<Attribute name="signingCertAlias">
                <Value>test</Value> //In production you can use separate cert for signing and encryption
</Attribute>
<Attribute name="encryptionCertAlias">
                <Value>test</Value> //In production you can use separate cert for signing and encryption
</Attribute>

Change All want*Encrypted properties (Only if you want everything encrypted. I did it when I tested)

 <Attribute name="wantAttributeEncrypted">
   <Value>true</Value>
  </Attribute>
  <Attribute name="wantAssertionEncrypted">
   <Value>true</Value>
  </Attribute>
  <Attribute name="wantNameIDEncrypted">
   <Value>true</Value>
  </Attribute>
 <Attribute name="wantAssertionEncrypted">
    <Value>true</Value>
</Attribute>

 All want*Signed properties (Only if you want everything Signed. I did it when I tested)

<Attribute name="wantPOSTResponseSigned">
          <Value>true</Value>
       </Attribute>
       <Attribute name="wantArtifactResponseSigned">
           <Value>true</Value>
       </Attribute>
       <Attribute name="wantLogoutRequestSigned">
           <Value>true</Value>
       </Attribute>
       <Attribute name="wantLogoutResponseSigned">
           <Value>true</Value>
       </Attribute>
       <Attribute name="wantMNIRequestSigned">
           <Value>true</Value>
       </Attribute>
       <Attribute name="wantMNIResponseSigned">
           <Value>true</Value>
 </Attribute>
In sp-extended.xml add realm name (In case you are using root you dont need to change anything just use the existing values)
metaAlias="/realm001/sp"
metaAlias="/realm001/attrQuery"
metaAlias="/realm001/pep"

In idp-extended.xml add realm name
metaAlias="/realm001/idp" 
metaAlias="/realm001/sp"

In sp-extended.xml set
 hosted="0"  (This tells openam that the entity you are trying  to upload (i.e. your SP) is remote and not locally hosted on Openam itself)

STEP 9:
Since we changed assertion consumer url in the sp.xml we need to update this url in IDP proxy, as IDP proxy will have Feldet  url which we have changed to keep Spring SAML extension happy.
1.   Go to  IDP Proxy (ie. http://idp.abc.com:8080/openam/UI/Login in my case)
2.   Navigate to  Federation > entity providers.
3.   Delete the service provider . ie. Entry which we added to generate Fedlet for our JSF app URL  (eg: http://abc.com:8080/TST)
4.   Make sure the same entity is also removed in Circle of Trust
5.   Click on import entity and select  sp.xml and sp-extended.xml respectively



STEP10:
Now in openam IDP (If you ar using proxy go to proxy) Under Federation > entity providers > your SP (ie. http://abc.com:8080/TST) and you should see signing and encryption with value of the certs.

NOTE:This note is applicable only if you are using openam as a proxy. IGNORE THIS is you are using openam as IDP.
Login in to Openam Proxy >Go to Federation  >  Entity Providers  (http://abc.com:8080/TST) -- Basically the remote Service provider )>  SP> Advanced >  IDP Proxy and make sure proxy count is set to 1 (i.e number one) and proxy url  is set to your IDP url (yes the proxy url is idp url).The proxy uses this value to send request to IDP.

STEP11: 
Verify that the acs url you have added in sp.xml is present in openam.
Login to IDP ( if you are using proxy login into openam proxy)> Click on Federation tab
Go to Entity providers section and click on the URL that we used to generate Fedlet (In this case we used http://abc.com:8080/TST )
While on SP tab go to “Services” screen scroll down to the section which has“Assertion consumer Service”
From: http://abc.com:8080/TST/fedletapplication
To: http://abc.com:8080/TST/saml/SSO/alias/realm001/sp

NOTE: I did not use single logout service. In case you want change the logout URL’s on this page. (Locally I changed all logout urls to “TST/saml/SingleLogout/alias/realm001/sp”)

Congratulations !!!! Your configuration to plugin SP with openam is complete.
We now need to focus on Spring code changes on you JSF web app.


 Spring SAML extension integration with your JSF application
or spring security saml tutorial
or spring security saml tutorial
or spring security jsf example

Here I will brief you about how to plugin spring code with your JSF application.

Please download the sample web application provided by Vladmir Schaufer and explore a bit


You should be able to download "spring-security-saml-1.0.0.RC2-dist.zip" or which ever is the most recent one. Use maven and do a build and you will get a deploy-able war file 


To run this example please read the java doc provided by the author 


Now in the zip file spring-security-saml-1.0.0.RC2\sample\src\main\resources\security\securityContext.xml
Let’s use this sample spring security xml file as a starting point for integrating our application.
If you read the documentation provided by Vladmir Schaufer you will now be familiar with the Spring security xml. However to make it work for our web app I really had to comment quite a few things.

So here is the Original Spring Security xml file (original-securityContext.xml)

Here is the modified file (rams-applicationContext-security.xml).This file has comments in each section indicating why I commented a xml entry. You can download the modified xml file from below url
 
I always had a question as why spring SAML uses the filters with urls patterns predefined.
  <security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
  <security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
  //We dont need metadata to be displayed comment this.

<!-- <security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/> -->
  <security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
  <security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
  <security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
  //We dont need Springdiscovery as we have one idp.So commented it.

<!--  <security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/> -->

This is how the spring filters will intercepts the urls.

Don't mess with this patterns.Thats the reason we changed the ACS and logout urls as mentioned in  STEP5.
Once you have this rams-applicationContext-security.xml all it needs is the below files in your path or classpath. (See the rams-applicationContext-security.xml)
  • sp.xml
  • idp.xml
  • java keystore with name keystore.jks  (I copied from openam for testing)- I will add one article on  keystores later.
  • Your openam IDP URL  (I used url as http://idp.abc.com:8080/openam 
NOTE: In case you are using proxy there is one section which says "ProxyCount" which you need to address. If you read the comment in the security xml you will know what to do.


Ok now if you see my modified spring xml the only code you need to write is the class com.tst.web.security.SAMLUserDetailsServiceImpl.java 
which is implementation for org.springframework.security.saml.userdetails.SAMLUserDetailsService
I will add the sample code here. I had integrated openam with Active directory and had configured openam to retrun the following attributes.
"ActiveDirGroups" and  "UserName" 
So when Openam sent the SAML Response it was sending these attributes. So we need to parse and build UserDetails object as below.

package com.tst.web.security;
package com.tst.web.security; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.saml.SAMLCredential; import org.springframework.security.saml.userdetails.SAMLUserDetailsService; /** * @author twreddy The SAMLUserDetailsService interface is similar to * UserDetailsService with difference that SAML data is used in order * obtain information about the user. So inspect the SAMLCredential * object and return such a data in a form of application specific * UserDetails object */ public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService { // SAML Response PAY load attributes. // Some of the attributes we get back in SAML RESPONSE // We mapped this in openam so it should be there in SAML response. public static final String GROUP_MEMBER_ATTR_NAME = "ActiveDirGroups"; public static final String USER_ID = "UserName"; private static Logger logger = LogManager.getLogger(FMSAMLUserDetailsService.class); /* * This is the method spring will invoke. */ public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException { logger = getLOSLogger(this); // Want to see if this object is null ... logger.info("credential=" + credential); if (credential != null) { String samlCredentilAsStr = ""; if (logger.isDebugEnabled()) { // I dont want read this object every time. // Will do only of we have enabled debugging. samlCredentilAsStr = ToStringBuilder.reflectionToString(credential); logger.debug("samlCredentilAsStr=" + samlCredentilAsStr); } String userId = getUserId(credential); logger.debug("userId=" + userId); UserDetails userDetails = getUserWithRoles(credential, userId); return userDetails; } throw new UsernameNotFoundException( "SAMLCredential is null. Cant extract " + GROUP_MEMBER_ATTR_NAME + " and or " + USER_ID + " in Saml Response. " ); } /** * Extracts all groups and creates a UserDetail object * and returns it. * @param credential * @param userId * @return */ private UserDetails getUserWithRoles(SAMLCredential credential, String userId) { UserDetails userDetails = null; // We dont have access to password ?? // So using name as password for now. List<SimpleGrantedAuthority> grantedRolesList = getGrantedAuthorities( GROUP_MEMBER_ATTR_NAME, credential); logger.info(" roles For :" + userId + " grantedRolesList=" + grantedRolesList); // This object needs userid and password. I dont have password // Faking it with user id. Password may really be needed when // you try to Authenticate this object using authManager. userDetails = new User(userId, userId, grantedRolesList); return userDetails; } /** * Reads the Attributes that are in SAML Pay load response. Our Group Meber * ship Is a long String: * CN=FILE_EDIT_USER,OU=Devtest,DC= We need to get only Group name which FILE_EDIT_USER * * @param name * @param credential * @return */ private List<SimpleGrantedAuthority> getGrantedAuthorities( final String name, final SAMLCredential credential) { List<SimpleGrantedAuthority> grantedRolesList = new ArrayList<SimpleGrantedAuthority>(); List<String> attrValueList = getAttributeValue(name,credential); for (String attrValue : attrValueList) { if (attrValue != null) { // All we are doing here is extracting the first part in the // group membership // eg: // CN=FILE_EDIT_USER,OU=Devtest,DC= We need to get only Group name which FILE_EDIT_USER logger.debug(" Raw Attribute=" + attrValue); String roleName = attrValue.split(",")[0].split("=")[1]; // We need just "FILE_EDIT_USER" logger.debug(" Cleaned up group name=" + roleName); logger.debug(" group name with case changed=" + roleName); SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority( roleName); grantedRolesList.add(grantedAuthority); } else { logger.warn("One of the Group attrValue was null."); } } return grantedRolesList; } /** * Given SAMLCredential inspects the object and returns the values * for give attribute name. * @param name * @param credential * @return */ public static List<String> getAttributeValue(final String name, final SAMLCredential credential) { List<String> attrValList = new ArrayList<String>(); Attribute attribute = credential.getAttributeByName(name); logger.debug(" Parsing name=" + name + " in SAMLCredential"); if (attribute != null) { List<XMLObject> attributes = attribute.getAttributeValues(); if ((attributes != null) && (attributes.size() > 0)) { for (XMLObject object : attributes) { XSString attrb = (XSString) object; String attrValue = attrb.getValue(); if (attrValue != null) { // clean unwanted strings here in the role logger.debug("name=" + name + " attrValue=" + attrValue); attrValList.add(attrValue); } } } } return attrValList; } /** * Reads the uid from SAML credential if present * @param credential * @return */ public static String getUserId(SAMLCredential credential) { String userId = null; List<String> userIdValueList = getAttributeValue(USER_ID, credential); logger.debug(" USER_ID="+ USER_ID +" userIdValueList=" + userIdValueList); if (userIdValueList.size() > 0) { userId = userIdValueList.get(0); } return userId; } }




So now you have spring security xml and the code to parse SAML repsonse ready. Just plugin. The srping xml in to your web.xml. Since the code above parsed the roles the user is we need to use those roles to enable or disable feature sin JSF pages which I will explain shortly.

In your webxml 
I have attached the sample web.xml
https://sites.google.com/site/reddymails/Home/web.xml?attredirects=0&d=1

    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
    </listener> 
    <context-param>
       <param-name>contextConfigLocation</param-name>
 <param-value>
  /WEB-INF/rams-applicationContext-security.xml
        </param-value>
      </context-param>
    <!--  Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
 <filter-name>springSecurityFilterChain</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>



How do to we read the User name from Spring security context ? 
I did some reading and here is code that saves you a day :)
The assumption is that your are sending "Username" as one of the attributes in SAML response.
Once you parse store it in Httpsession that way you don't run this code multiple times for same user.

public static final String USER_ID = "UserName";

  public String getCurentUserName(){
// Read from Security context as SAML Pay loads gets  your name.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SAMLCredential samlCredential = (SAMLCredential) authentication.getCredentials();
String userName = getUserId(samlCredential);
return userName;
}

 /**
 * Reads the uid from SAML credential if present
 * @param credential
 * @return
 */
public static String getUserId(SAMLCredential credential) {
  String userId = null;
List<String> userIdValueList = getAttributeValue(USER_ID, credential);
logger.debug(" USER_ID="+ USER_ID +" userIdValueList=" + userIdValueList);
 if (userIdValueList.size() > 0) {
  userId = userIdValueList.get(0);
 }
 return userId;
}

With this you are done with single sign on. Howevere If you want to use Spring Security you can read th below few lines
Once you have all this code you can plugin spring role based security if you need.

Just follow these steps
<!--  To add Security tag tld to  JSF you can read more at.
more at 
http://static.springsource.org/spring-webflow/docs/2.2.x/reference/html/ch13s09.html
  http://doanduyhai.wordpress.com/2012/02/26/spring-security-part-v-security-tags/
-->

Assuuming you have configured the Spring security tld now you can add name space in JSF page as shown below.
xmlns:security="http://www.springframework.org/security/tags"

And inside your JSF page now you can use tags like 

rendered="#{security:areAnyGranted('FILE_READ_GROUP,FILE_EDIT_GROUP')}">
rendered="#security:areAllGranted('FILE_ALL_OPERATIONS_GROUP)"
disabled="#{security:areNotGranted('FILE_READ_GROUP)}">

Where FILE_READ_GROUP, FILE_ALL_OPERATIONS are Active directory groups the current user is in.

Hope this article take some pain of integrating openam with Spring SAML and also helps you in Spring Security integration with JSF application.
 
NOTE:If your web application is .net based you can try using .net fedelt
 provided by openam.I don't have much knowledge to comment on .net.
If you like my articles or have some suggestion feel free to drop a message.


Saturday, March 30, 2013

SSO for Java or .Net Web based applications using Openam

  • Single Sign on for Java/J2ee based Web applications
  • Single sign on using  Spring Security SAML Extension and  Role based authentication using Spring Security 
  • Single sign on Java
  • Single sign on for JSF based web application.

Introduction: Single Sign On (SSO) for Web applications using OPENAM 

Why do we need SSO ?
Say a user is logged in to one application and clicks on a link to another application and in this case if you don't want the user to enter his userid/password again but based on some token you know that "Yes the person say johnsmith@xyz.com" is already authenticated so he can access your second application.
Its like you log in to gmail and from there you can navigate to youtube or google+ or blogspot without entering password. This can be facilitated by an IDP and each time the request goes IDP know that yes "person johnsmith@xyz.com" was authenticated already and his token id is "axxbv67745554wedxyXcDb".


OpenAM is and identity provider (and more) formerly known as OpenSSO was owned by Sun which was later taken over by oracle. However Forgerock has it own source code and its called OpenAM and maintains it . You can download and deploy openam as web based J2ee application on any application server like - Tomcat, Websphere , Jboss or Weblogic.

Before getting in to the details of why we need OpenAM lets know some terminologies.I will describe them in my own words as those technical jargon's took me a while to catch up.

IDP:(Identity provider) - A module/application that can authenticate and provide you a security token which can be used in singe sign on.
SP:(Service provider):  A system that allows users (Or principal) to authenticate against IDP.
E.g.: We have a JSF 2.0 web application that talks to openam.
Here our web application is SP, Openam is IDP and I am logging in to our webapp I am the principal (user).
Realm: A realm is the unit that used to organize configuration information. Authentication properties, authorization policies, data stores, subjects (including a user, a group of users, or a collection of protected resources) and other data can be defined within the realm.
Lets say your company has Active directory for authenticating user and you want to use that as data store that the IDP can finally use. In the realm you can to use this ActiveDirectory.

Circle of Trust: COT is a federation of any number of service providers (and at least one identity provider) with whom principals can transact in a secure and apparently seamless environment.
In lay man terms we add a list of IP addresses say the SP urls,IDP url all in to once circle of trust. If they are not in same COT openam doesn't allow us to send request.
Eg: Say your web application (SP) is at www.xyz.com/shopnow and your identity provider url is www.myidp.com/openam then you need to add both these urls to one circle of trust in OpenAM.

Realm and Circle of Trust. How are they connected ?
- This is what I think. 
Realm =>Can have many Data stores or Identity Stores.
COT =>Will have many host names or Ip address (ie. SPs, IDP)
When we create a new Circle of Trust you need to specify the realm name,.
COT ===> Is linked to Realm. 
 For sake of discussion lets call our sample circle of trust as "COT1" and realm as "Relam1"
Where 
COT1 = has (SP -www.xyz.com/shopnow  and IDP - www.myidp.com/openam)
Realm1 == Is configured to use Active Directory as Identity store for Authentication.
So by doing this we are telling hey if the request comes from SP ( www.xyz.com/shopnow) use the IDP (www.myidp.com/openam) because they are in same Circle of Trust = COT1. Now the IDP sees that COT1 is linked to Realm1 and so it uses the Active directory checks the user credentials and does the Authentication.

We can have many circle of trusts linked to one realm.  Here is my visualization.




Fedlet: A client that we can generate using OpenAM. The client generated can be for a .Net or a Java based Fedlet. In Java the Fedlete can be used plugged into existing your web application  if your just doing Single sign on and not role based authorization. In my case I had to allow the user to sign in and also check in what groups the user is and based on that I had to block some pages so we had to use Spring saml extension to talk to IDP instead of Fedlet. At least for initial testing of OpenAM set up Fedlet was very useful.

SAML: Security Assertion Mark Language is an XML based data format that flows between IDP and SP when a principal is trying authentication and/or authorization. You dont need to worry about this as OpenAM generates this for you when it sends response and in your Web application if you are u


There could be a situation where you may have to integrate more than one IDP to your SP in that case you need to have another instance of OpenAM that can act like IDP proxy.
So your configuration will look like

SP (Your Java Web app or Generated Fedlet) <===> IDP Proxy (openam)   <=====>  (IDP1, IDP2.....)
Where
IDPProxy is an OpenAM instance
IDP1, IDP2- Are Identity providers which can be OpenAM or any SAML2 Complaint IDPs.

I have seen in openam wiki where they have given an example to install 3 instances of openam so that one is IDP, other is Proxy and 3rd openam instance as SP. That is way complex.

For simple scenario you need just one openam instance which acts as IDP and generate a Fedlet and that will act as SP.For just SP you don't need another openam instance. Also consider using proxy only if you are integrating with more than one IDP so that the SP can talk to proxy and need not worry about multiple IDP's. Here your proxy is acting like a Facade and hides complexity of multiple IDP's

So for simple scenario it will look like
SP (Your Java Web app or Openam generated Fedlet client) <===> IDP (openam)

Here SP should be able to send and receive SAML requests/responses.

Here is link  for some sample saml request and responses. 
https://rnd.feide.no/2007/12/10/example_saml_2_0_request_and_response/
Don't panic you will not create this xml OpenAM, Spring Saml extension or Fedlet does the job for you.


In the next article I will explain how to install OpenAM as IDP and how you can plugin Spring SAML extension and Spring Security to you web app to talk to OpenAM and trouble shooting.
Before I continue further I want to thank two people for there out standing support and help and answering all my stupid questions during our implementation of SSO  solution and integrating with Spring Saml extension along with Spring Security.
Vladmir Schafer: Author of Spring Saml Extension library
Peter Major and the entire OpenAM community.

I have a added new article on how to intgerate a Java based web applications with openam for single sign on . The application can be a JSP or Struts or JSF based web app.
All can use this tutorial.
http://reddymails.blogspot.com/2013/06/integrating-jsf-web-applicataion-with.html

If you like my articles or have any suggestions please leave a comment.