Saturday, August 17, 2013

SSL Certificates or SSL Certs



In this article I will answer the following questions.
How to create a SSL cert?
How to obtain SSL cert ?
How do I get my cert signed ?
How  to get a signed cert?
How to install a signed ssl certificate to keystore ?
How to convert jks to pfx ?
what is jks keystore?
what is pfx  keystore?
what is a keystore ?

I was working on some security related project and wanted  to get a signed cert installed.So I did read few articles and the outcome of that is what I have explained below.

Keystore is a file (a database) to store your public/private keys.
Keystore can be in different formats - Most populare ones are JKS, PKCS12.
JKS is a Java-specific file format to store keys in key store. your keystore can be .keystore or abc.jks or any other name.

.p12 or .pfx for type "PKCS12" - (Personal Information Exchange)  - Is another format to store public/private keys.PKCS just means Public-Key Cryptography Standards)
The .pfx file extension most often indicates a Personal Information Exchange file, most frequently used on a Windows operating system or .NET framework.


To get a signed cert we need the following

Step1. Generate a Key pair using Keytool
Step2. Generate a CSR (Cert Signing Request) for the Keys you generated in step1.
(Read more for to find what CSR contains http://en.wikipedia.org/wiki/Certificate_signing_request)
Step3: Send the CSR file to CA (Certifying Authority) like Verisign or Digicert or Thwart.
Step4: Import the signed.Once you receive the signed cert from CA which may be a .p7b (PKCS #7 Certificate) it will have 3 certs within it
                - your cert generated in step1 which is signed
                - CA root cert
                - CA intermediate cert

Step5: Now you need to add back the signed cert sent by CA.This process involves updating your keystore with new signed public key. Your private key will still be the same. Since you are adding the signed public key we also need to add CA root cert and CA intermediate cert. I will explain below.



STEP1: Generate a key pair
===========================
keytool -genkeypair -alias testcertforsigning -storepass
secret -keypass secret -validity 1825 -keystore my_java_keystore.jks -keyalg RSA
 -keysize 2048 -storetype JKS -dname "CN=*.xyz.com, OU=Development,
 O=xyz.com, L=Bangalore, S=Karanataka, C=IN"
where   testcertforsigninng - is the cert name
                secret - I used this as both store password and cert password. you can use different strings                       
                validity - 1825 days  - 5 years
                Rest is all obvious which tells what algorithm, key size (use 2048 or higher for better security) and what your company name is.
                CN=*.xyz.com ==> Tells that this cert is applicable for all url’s that end with *.xyz.com assuming in your company you have url’s like app1.xyz.com, app2.xyz.com, app3.xyz.com to access your application.

Now if you list the contents of Key store
keytool -list -v -keystore my_java_keystore.jks
-storepass secret

NOTE: If you have both public/private key entry after running key tool you will see
Your key store contains 2 entries

Alias name: testcertforsigning
Creation date: Apr 18, 2013
Entry type: keyEntry
Certificate chain length: 1 ===>
Certificate[1]:
{The actual cert information will be printed here. Excluded that intentionally.}

The Entry type: keyEntry ==> indicates that you have both public/private key pair else the type:
Certificate chain length: 1 ===> Tells you have one cert (This is cert doesn’t not have root cert and intermediate cert yet so the length is one.)

Step2 and 3: Generate a CSR (Cert Signing Request) for the Keys you generated in step1.
===============================================================================
keytool -certreq -keystore my_java_keystore.jks
-storepass secret -alias testcertforsigning 
-file xyz_cert_signing_req.csr

More info on csr file contents: http://en.wikipedia.org/wiki/Certificate_signing_request
Remember this file will only have your public key and some info about your organization. You never  will or should share private key.
Now send this xyz_cert_signing_req.csr to CA (certifying authority) like verisign or digicert. (Yes you need to pay to get a signed cert :) )


Step4: This is very important step. Here if you try to import just your signed cert you will get error.
Follow these steps:
-          Once you receive your signed cert from CA, let’s call this as xyz_cert_signing_req.p7b.
-          Double click the file and you should see something similar (your  CA name could be different )





Now click on each cert (i.e. *.xyz.com, Digicert High Assurance CA-3, Digicert High Assurance EV Root CA) and a popup launches as shown below and now you should be able to save each cert public key separately, Choose Base-64 encoded X.509 (.CER) format when saving.



 
 Certificate export Wizard



Let’s call these exported cert’s as
RootCA.cer
HighAssuranceIntermediateCA3.cer
xyz_cert_signing.cer

If you open them in text editor you will see something like

-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
…..
….
-----END CERTIFICATE-----

Now combine the three * .cer files in to one file (You can manually copy or use a script)
Let’s call this as xyz_cert_signing_combine.txt
This combined file will have all 3 certs (root,intermediate and your xyz_cert_signing.cer) contents
-----BEGIN CERTIFICATE-----
Contents of RootCA.cer  here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Contents of HighAssuranceIntermediateCA3.cer  here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Contents of xyz_cert_signing.cer here
-----END CERTIFICATE-----


STEP5:  Now import this signed public key along with its root, intermediate cert too your key store.
So you  need to use the combined file xyz_cert_signing_combine.txt
(I am using keytool which is part of java jdk)
   
keytool -import -trustcacerts -file xyz_cert_signing_combine.txt -keystore my_java_keystore.jks  -alias testcertforsigning  -storepass secret  -keypass secret

 Now if you list your keystore you will see root cert, intermediate cert and your signed public key sitting along with your private key.

If some other app asks your signed public key you can send them xyz_cert_signing_req.p7b  in which case they will extract root cert, intermediate cert and your signed public key. However if they want to install to the keystore , they may have to combine all 3 keys like I explained and install it differently

keytool -import  -file
 xyz_cert_signing_combine.txt
  -keystore my_java_keystore.jks  -alias testcertforsigning  -storepass secret  

(NOTE: The keypass and –trustcacerts is not required as we are not updating existing public-private key instead just adding a public key. It makes sense as without the root ca cert and intermediate cert there is no way the other app can trust if your public key is signed by the right authority.)

To convert JKS to PFX
keytool -importkeystore 
 -srckeypass secret –destkeypass meow123 
 -srcstorepass secret -deststorepass meow123 -srcalias testcertforsigning  -destalias testcertforsigning  -srckeystore  my_java_keystore.jks  -destkeystore  not_java_keystore.pfx  -deststoretype PKCS12
If you are adding more than one cert repeat the
-srcalias   -destalias  options more than once.


In case you want to export the public key only

TO LIST KEYSTORE:
=================
--Java Key store
 keytool -list -v -keystore my_java_keystore.jks -storepass secret

--PFX (Personal Information Exchange)  key store.
 keytool -list -v -keystore not_java_keystore.pfx -storepass secret -storetype PKCS12


NOTE: If you have both public/private key entry after running key tool you will see
Your keystore contains 2 entries
Alias name: testcertforsigning
Creation date: Feb 1, 2022
Entry type: PrivateKeyEntry
Certificate chain length: 4
Certificate[1]: {The actual cert information will be printed here. Excluded that intentionally.}


The Entry type: PrivateKeyEntry indicates that you have both public/private key pair hence the type:


Incaser someone sent you ".pfx" file  , In java you can specify the  "pfx" file as keystore and "Jks" file as truststore by importing ".cer" files to  your java keystore.


In java code you can  do this are export the same using -D option.

            Properties props = System.getProperties();
    // to enable debugging 
        props.setProperty("javax.net.debug","all");

 //Mostly will have CA certs 
          props.setProperty("javax.net.ssl.trustStore","C:\\Program Files\\Java\\openjdk-11\\lib\\security\\cacerts");
      props.setProperty("javax.net.ssl.trustStorePassword", "changeit");
          props.setProperty("javax.net.ssl.trustStoreType","PKCS12");
         
          props.setProperty("javax.net.ssl.keyStore", "C:\\Rama\\Project\\RamaFinancialTest2022.pfx");
          props.setProperty("javax.net.ssl.keyStorePassword", "abcd");
          props.setProperty("javax.net.ssl.keyStoreType","PKCS12"); 
 //In case you want to control Ciphersuites based on what the server is supporting
//props.setProperty("jdk.tls.client.cipherSuites","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
  //props.setProperty("jdk.tls.server.cipherSuites","TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");

Though in java its common to use the same "jks" (cacert file mnetioned above) as keystore and trust store. In our case a external client sent the ".pfx" file which any way java can read so we used that as Keystore as it as priavetKeyEntry (public and priavet key chain) and extracted the remaining root and inetermedicate certs and added to trust store. 

More info:

Please read 

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.