Thursday, October 31, 2013

Install and configure OpenAM for Spring SAML (on Windows)


  • assign a FQDN to 127.0.0.1 in hosts (like localhost.domain.home)
  • Install Tomcat as a service (7 at the moment this post was written)
  • Change the default HTTP port from 8080 to whatever value is required to avoid conflicts (in ...\Tomcat 7.0\conf\server.xml)
  • Restart the service
  • Download OpenAM distribution (I have used OpenAM-12.0.0-SNAPSHOT_nightly_20131021since the stable 10 version had a known issue on signing SAML assertions due to a problem in JDK 7_u25)
  • Extract distribution content, rename OpenAM-12.0.0-SNAPSHOT.war to openam.war
  • Copy openam.war to ...Tomcat 7.0\webapps
  • Browse to http://<server>:<port>/openam
  • Run the custom configuration (the default has a problem with generating the default domain for cookies) 
    • Use .domain.home as cockie domain (notice the leading dot)
    • Use the embedded LDAP (OpenDJ)
  • When the configuration is finnished login with amadmin/<password>
  • Choose "Create a hosted Identity Provider"
    • Choose the test signing key (or another if previously installed) if your SP requires signed/encripted assertions
    • Choose a name for the circle of trust
    • Press Configure
  • Add a SP in the same circle of trust:
    • Choose "Create a remote Service Provider"
    • Use the option to upload the metadata from a file (or specify on URL)
    • Press Configure
  • Configure attributes to be retrieved from data store
    • Go to Access Control->Top Level Realm->Data Stores->Embedded
    • Use the New Value/Add to add required (missing) attributes to be retrieved from the data store (like isMemberOf); 
      • attribute list is more generic and notr specific to the actual data store
      • use a LDAP browser to see actual attributes
  • Configure the mapping between required  assertion attributes (to be sent in SAML Response) and data store attributes:
    • Go to Federation->target IdP->Assertion Processing
    • In Attribute Mapper->Attribute map section use New Value->Add to add mappings (like isMemberOf=isMemberOf)
    • Save
  • Restart OpenAM or Tomcat; without restarting previously configured attribute mapping will not take place
Adding users:
  • Access Control->Top Level Realm
    • Group:add new groups
    • User: add/configure users
      • Be sure to fill in the field that the SP has configured as a potential Name ID (like email) otherwise an exception will be thrown (and recorded in OpenAM log) and an error will be sent back as a SAML Response

On non expected behavior check logs in openam configuration folder (default c:\openam): 
  • C:\openam\openam\debug
  • C:\openam\openam\log





Browsing OpenAM default LDAP store (OpenDJ)

When you need to configures attributes that will be sent in SAML response back to Service Provider you might need to know what actually is available and what are the specific names/formats.

For that purpose you need a LDAP browser (like Softera free tool).

  • Be sure OpenAM is started
  • Connect to embeded LADP using:
    • Host: localhost
    • Port: 50389
    • User Principal): cn=Directory Manager
    • Password: the password you initially configured for amadmin
  • Be sure to select (on object's properties): Display operational attributes/Display all

@Autowired in web applications

"Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities." (http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/beans/factory/annotation/Autowired.html)

Almost all samples on this topic use command line Java applications that programatically load the configuration file that maps the interface to its implementation class. In JSF based applications use the context param tag in web.xml to achieve the same result.

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/security/samlUserDetailsService4Autowire.xml
            classpath:/security/securityContext.xml
        </param-value>
</context-param>
Please notice that the order of configuration files is important and is dictated by dependency injection 'dependencies' (at the moment of injection the required instances to be injected must already exist)

Wednesday, October 23, 2013

Decoding SAML Request/Response

You can use online decoder provided by ssocircle: https://idp.ssocircle.com/sso/toolbox/samlDecode.jsp
If sent as URL parameter the request/response must be decoded with the redirect option.
The actual algorithm for obtaing the encoded string is as follows:
  1. Gzip deflate the request/response if sent as query parameter (no change for POST parameters)
  2. Convert to Base64
  3. URL encode the result

Configure Galssfish (3.1.2.2) for HTTPS


  1. Prepare a certificate (issued for the FQDN of the server running Glassfish) in PKCS#12 format (p12 extension) containing the private/public key pair; OpenSSL can be used to generate a CA and generate afterwards test certificates
  2. In target domains/<domanin>/config/cacerts.jks add* CA public certificate; default keystore password is 'changeit'
  3. In target domains/<domanin>/config/keystore.jks add the p12 certificate; use the same password as the keystore ('default value 'changeit')
  4. Open adnin console, go to server configuration and expand it to Network Config->Network Listners->network-listner-2, SSL tab.
  5. Replace the default test certificate name (s1as) with the keystore name of the newly added certificate
  6. Apply changes and restart glassfish
*You can use Portecle GUI based tool to manage keystores

Run Spring SAML Extension sample app.

Prerequisites:

  1. NetBeans 7.4
  2. Glassfish 3.1.2.2
  3. A PKCS#12 format cerificate for SAML requests signing
  4. Spring SAML Extension sample app downloaded (http://docs.spring.io/spring-security/site/extensions/saml/)

  • Add the certificate in  samlKeystore.jks (in resources\security)
  • Open project in NetBeans
  • Change the default securityContext.xml (will be used later):
    • configure the newly added certificate in keyManagerBean as an entry in constructor parameters
                             <entry key="localhostsaml" value="nalle123"/>
    • configure the metadataGeneratorBean constructor parameter:

                            <bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                               <property name="entityId" value="urn:myid:saml"/>
                               <property name="signMetadata" value="false"/>
                               <property name="bindingsSSO" >
                                 <list>
                                    <value>POST</value>
                                 </list>
                              </property>
                           </bean>
  • save the  and NetBeans will deploy the war
  • run the metadata generation page : https:// localhost.myserver.local:8181/spring-security-saml2-sample/saml/web/metadata; use the real FQDN so that metadata will be generated with actual values
  • Click on the link "Generate new service provider metadata)
  • Change the values of:
    • Entity ID and Entity alias to same urn as the entityId previously configured (eg urn:myid:saml)
    • SigningKey and EncriptionKey to the one added in samlKeystore.jks (localhostsaml in our sample)
    • Sign Metadata: No
    • Single sign-on bindings: unckeck Artifact and choose as default the POST one
    • Enable IDP Discovery profile:: No
  • Press Generate Metadata
  • Copy The content of Metadata texta area andcopy the content in a newly created sp.xml, placed in resources\security
  • In securityContext.xml add a constructor parameter for "metadata" bean:
                <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                    <constructor-arg>
                        <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                            <constructor-arg>
                                <value type="java.io.File">classpath:security/sp.xml</value>
                            </constructor-arg>
                            <property name="parserPool" ref="parserPool"/>
                        </bean>
                    </constructor-arg>
                    <constructor-arg>
                        <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                            <property name="local" value="true"/>
                            <property name="alias" value="urn:myid:saml"/>
                            <property name="securityProfile" value="metaiop"/>
                            <property name="sslSecurityProfile" value="pkix"/>
                            <property name="signingKey" value="localhostsaml"/>
                            <property name="encryptionKey" value="localhostsaml"/>
                            <property name="requireArtifactResolveSigned" value="false"/>
                            <property name="requireLogoutRequestSigned" value="false"/>
                            <property name="requireLogoutResponseSigned" value="false"/>
                            <property name="idpDiscoveryEnabled" value="false"/>
                        </bean>
                    </constructor-arg>
                </bean> 
Please notice that the ExtendedMetadata   content is copy/pasted from metadata generation result (Configuration text area)  
  • Un comment and update the tag, values is actually the value of the alias (we have used the same value for Id and alias): 
             <property name="hostedSPName" value="urn:myid:saml"/>
  • Be sure that the only uncommented tag for defaultIDPis the following:
             <property name="defaultIDP " value="http://idp.ssocircle.com"/>
  • Go to http://www.ssocircle.com/en/ and create an account
  • After login go to Manage Metadata and create a new Service Provider:
    • Provide the FDQN as the entityId (urm:myid:saml in our sample)
    • Mark all attributes
    • Paste the content of sp.xml in the metadata information text area
  • Log out from ssocircle
  • Run the application; you should be redirected to ssocircle and after entering usernam/password redirected back to index.jsp showing information received in  SAML Response