» AWS SSO with Shibboleth IdP 3.3.0 in CentOS 7, with two separate LDAP schemas for Users and Groups

Below steps shows how to setup AWS single sign-on using Shibboleth IdP 3.3.0, when you have two separate LDAP schemas to store the user and group details. Usually, user's LDAP attributes would show the group memberships for that user, but in my case, my enterprise LDAP had two separate schemas to store the user information and group membership information. So, I had to create two Shibboleth attribute-resolver configurations to do the user search in one schema and group search in another, and then do a single sign-on based on that. This is an update to the already available AWS whitepaper here which explains the SSO setup using IdP version 2.0. I couldn't setup IdP 3.3.0 by following those steps, since it required few changes for 3.3.0. As mentioned in the IdP 2.0 whitepaper, it is assumed that the IdP will be hosted at idp.example.com. Replace this with your actual IdP FQDN. It is also assumed that you have adequate experience with Linux and AWS. I am not explaining the Shibboleth IdP concepts here, requesting you to get a fair understanding of the terms Shibboleth uses, before starting this configuration. Please refer the original AWS whitepaper if you need more clarity on the overall IdP steps described here.

Additional reference:
https://wiki.shibboleth.net/confluence/display/IDP30/ApacheTomcat8
https://wiki.shibboleth.net/confluence/display/IDP30/Installation

[root@linux1 ~]# wget -O apache-tomcat-8.0.41.tar.gz http://www.us.apache.org/dist/tomcat/tomcat-7/v8.0.41//bin/apache-tomcat-8.0.41.tar.gz [root@linux1 ~]# cd /opt; tar -xvzf /root/apache-tomcat-8.0.41.tar.gz; cd ~ [root@linux1 ~]# wget http://shibboleth.net/downloads/identity-provider/latest/shibboleth-identity-provider-3.3.0.tar.gz [root@linux1 ~]# cd /opt; tar -xvzf ~/shibboleth-identity-provider-3.3.0.tar.gz ; cd ~ [root@linux1 ~]# yum install -y java-1.8.0-openjdk-devel [root@linux1 ~]# export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.121-0.b13.el7_3.x86_64/ [root@linux1 ~]# cd /opt/shibboleth-identity-provider-3.3.0/bin/ [root@linux1 bin]# ./install.sh Source (Distribution) Directory (press to accept default: [/opt/shibboleth-identity-provider-3.3.0] Installation Directory: [/opt/shibboleth-idp] Hostname: [centos7.localdomain] idp.example.com SAML EntityID: [https://idp.example.com/idp/shibboleth] Attribute Scope: [localdomain] Backchannel PKCS12 Password: passw0rd Re-enter password: passw0rd Cookie Encryption Key Password: passw0rd Re-enter password: passw0rd Warning: /opt/shibboleth-idp/bin does not exist. Warning: /opt/shibboleth-idp/dist does not exist. Warning: /opt/shibboleth-idp/doc does not exist. Warning: /opt/shibboleth-idp/system does not exist. Warning: /opt/shibboleth-idp/webapp does not exist. Generating Signing Key, CN = idp.example.com URI = https://idp.example.com/idp/shibboleth ... ...done Creating Encryption Key, CN = idp.example.com URI = https://idp.example.com/idp/shibboleth ... ...done Creating Backchannel keystore, CN = idp.example.com URI = https://idp.example.com/idp/shibboleth ... ...done Creating cookie encryption key files... ...done Rebuilding /opt/shibboleth-idp/war/idp.war ... ...done BUILD SUCCESSFUL Total time: 1 minute 5 seconds [root@linux1 ~]# cd /opt/apache-tomcat-8.0.41/conf [root@linux1 conf]# vi server.xml # Comment out the section for 8080, replace 8443 as 443, add key store details for 443 <Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/opt/shibboleth-idp/credentials/idp-backchannel.p12" keystorePass="passw0rd" keystoreType="PKCS12" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="443" /> [root@linux1 bin]# vi /opt/apache-tomcat-8.0.41/conf/tomcat-users.xml <user username="root" password="passw0rd" roles="manager-gui"/> [root@linux1 conf]# mkdir -p Catalina/localhost/ [root@linux1 conf]# cd Catalina/localhost/ [root@linux1 localhost]# vi idp.xml <Context docBase="/opt/shibboleth-idp/war/idp.war" privileged="true" antiResourceLocking="false" swallowOutput="true" /> [root@linux1 # cd /opt/shibboleth-idp/edit-webapp/WEB-INF/lib [root@linux1 lib]# wget https://build.shibboleth.net/nexus/service/local/repositories/thirdparty/content/javax/servlet/jstl/1.2/jstl-1.2.jar [root@linux1 lib]# cp /opt/shibboleth-idp/webapp/WEB-INF/web.xml /opt/shibboleth-idp/edit-webapp/WEB-INF/ [root@linux1 lib]# vi /opt/shibboleth-idp/edit-webapp/WEB-INF/web.xml # Add this in the beginning <context-param> <param-name>idp.home</param-name> <param-value>/opt/shibboleth-idp</param-value> </context-param> # Add any organization logos to /opt/shibboleth-idp/edit-webapp/images, smaller size logo is preferred. Optionally, edit the file /opt/shibboleth-idp/system/messages/messages.properties to replace the values for below variables, and any more values as needed. These values are used in the IdP login screens.
[root@linux1 lib]# vi /opt/shibboleth-idp/system/messages/messages.properties idp.login.username = Enter Your E-Mail idp.login.password = Enter Your Password idp.url.password.reset = https://your.idmanager.site/password idp.url.helpdesk = https://your.ticketing.site idp.title = Bejoy AWS SSO idp.title.suffix = Error idp.logo = /images/logo.jpg idp.logo.alt-text = Logo idp.message = An unidentified error occurred. idp.footer = Bejoy AWS SSO root.title = Bejoy AWS SSO root.message = <a href="/idp/profile/SAML2/Unsolicited/SSO?providerId=urn:amazon:webservices">Click here to login to AWS using intranet ID.</a> root.footer = Bejoy AWS SSO [root@linux1 lib]# cd /opt/shibboleth-idp/bin/ [root@linux1 bin]# ./build.sh # Edit /opt/apache-tomcat-8.0.41/webapps/ROOT/index.jsp to replace the entire contents with this single line, so that tomcat will redirect you to the SSO login page when you open tomcat home page. [root@linux1 bin]# vi /opt/apache-tomcat-8.0.41/webapps/ROOT/index.jsp <% response.sendRedirect("/idp/profile/SAML2/Unsolicited/SSO?providerId=urn:amazon:webservices"); %> [root@linux1 lib]# vi /opt/apache-tomcat-8.0.41/conf/context.xml # Uncomment the below section to disable session persistence <Manager pathname="" /> # Keep a copy of default log configuration, so that we can revert back to normal logging once everything is working fine [root@linux1 bin]# cp /opt/shibboleth-idp/conf/logback.xml /opt/shibboleth-idp/conf/logback.xml.org [root@linux1 bin]# vi /opt/shibboleth-idp/conf/logback.xml # Enable all level= as DEBUG and other log level values to DEBUG. Click here for a sample DEBUG enabled log configuration file [root@linux1 bin]# vi /opt/shibboleth-idp/conf/access-control.xml # Edit below section to add the subnet details from where this IdP needs to be accessed <entry key="AccessByIPAddress"> <bean id="AccessByIPAddress" parent="shibboleth.IPRangeAccessControl" p:allowedRanges="#{ {'127.0.0.1/32', '::1/128', '10.0.0.0/8'} }" /> </entry> Click here for a sample access-control configuration file [root@linux1 bin]# /opt/apache-tomcat-8.0.41/bin/startup.sh; tail -f /opt/apache-tomcat-8.0.41/logs/catalina.out

Open https://idp.example.com/idp/status, it should display the details of OS and services. Download /opt/shibboleth-idp/metadata/idp-metadata.xml from the IdP server and use it to create a SAML Identity provider in AWS.

While creating the identity provider in AWS, select:

Provider Type: SAML, Provider Name: BejoyIdP330, Upload the file downloaded above from IdP.

Note down the complete ARN of the Identity provider -> arn:aws:iam::123456789012:saml-provider/BejoyIdP330

Create new IAM role with type as 'Identity Provider Access' and 'WebSSO Access', and select the identity provider created in previous step as the SAML provider. Associate necessary Groups/Permissions corresponding to the groups in LDAP, like Bejoy-AWS-ReadOnly, Bejoy-AWS-SysAdmins. For the roles, you can put additional conditions so that it can be assumed only with certain criteria like below (you can refer any other attributes like eduPersonPrimaryOrgUnitDN which gets released by IdP to AWS to do this condition validation)

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRoleWithSAML", "Principal": { "Federated": "arn:aws:iam::123456789012:saml-provider/BejoyIdP330" }, "Condition": { "StringEquals": { "SAML:aud": "https://signin.aws.amazon.com/saml" } } } ] }

# Sample condition to allow this role only if the department is HR "Condition": { "StringEquals": { "SAML:aud": "https://signin.aws.amazon.com/saml" }, "ForAnyValue:StringEquals": { "SAML:eduPersonPrimaryOrgUnitDN": "ou=hr,dc=example,dc=com" } }

Note down the role ARNs as well:

arn:aws:iam::123456789012:role/Bejoy-AWS-ReadOnly
arn:aws:iam::123456789012:role/Bejoy-AWS-SysAdmins

Modify /opt/shibboleth/conf/ldap.properties to update your LDAP server details, user search base, and groups search base.

idp.authn.LDAP.ldapURL = ldap://myldap.example.com idp.authn.LDAP.useStartTLS = false idp.authn.LDAP.useSSL = false idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining idp.authn.LDAP.baseDN = ou=users,o=example.com idp.authn.LDAP.baseDNGroups = ou=groups,o=example.com idp.authn.LDAP.subtreeSearch = true idp.authn.LDAP.userFilter = (preferredIdentity={user}) idp.authn.LDAP.dnFormat = uid=%s,ou=users,o=example.com idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL} idp.attribute.resolver.LDAP.connectTimeout = %{idp.authn.LDAP.connectTimeout:PT3S} idp.attribute.resolver.LDAP.responseTimeout = %{idp.authn.LDAP.responseTimeout:PT3S} idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN:undefined} idp.attribute.resolver.LDAP.baseDNGroups = %{idp.authn.LDAP.baseDNGroups:undefined} idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined} idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined} idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true} idp.attribute.resolver.LDAP.searchFilter = (preferredIdentity=$resolutionContext.principal)

Modify the file /opt/shibboleth/conf/attribute-resolver.xml as this sample file (replace the role names, IdP names as required)

Modify the file /opt/shibboleth/conf/attribute-filter.xml as this sample file.

Modify /opt/shibboleth/conf/relying-party.xml (sample here) & metadata-providers.xml (sample here) to make Shibboleth talk to AWS.

Restart Tomcat to reflect the configuration changes


[root@linux1 ~]# /opt/apache-tomcat-8.0.41/bin/shutdown.sh; sleep 10; /opt/apache-tomcat-8.0.41/bin/startup.sh; tail -f /opt/apache-tomcat-8.0.41/logs/catalina.out
[root@linux1 ~]# tail -f /opt/shibboleth/logs/idp-process.log
To test if the IdP is able to create the SAML for AWS assertion, run this. This should output a SAML xml with proper AWS roles and other values as defined.

[root@linux1 ~]# cd /opt/shibboleth-idp/bin; ./aacli.sh --requester "urn:amazon:webservices" --principal bejoy@email.com
(http://localhost/idp/profile/admin/resolvertest?requester=urn%3Aamazon%3Awebservices&principal=bejoy%40email.com) http://localhost/idp/profile/admin/resolvertest?requester=urn%3Aamazon%3Awebservices&principal=bejoy%40email.com
# replace 'http' with 'https' for testing the URL you get from this script, and open it in browser.

Open URL https://idp.example.com/idp/profile/SAML2/Unsolicited/SSO?providerId=urn:amazon:webservices to open the Shibboleth IdP login page and fill in the user name password with your intranet ID and password, this should login to AWS with the appropriate role based on your LDAP group membership. (Copy & paste this URL to your browser if the link in browser says https://idp.example.com/idp/Authn/UserPassword instead of the above complete URL)

If everything works fine, replace /opt/shibboleth-idp/conf/logback.xml with the original base logging file and restart tomcat

[root@linux1 ~]# /opt/apache-tomcat-8.0.41/bin/shutdown.sh; sleep 10; /opt/apache-tomcat-8.0.41/bin/startup.sh; tail -f /opt/apache-tomcat-8.0.41/logs/catalina.out