- Prepare your Active Directory
- Installing the Fediz Demo Application
- Installing Fediz IDP and a Kerberos enabled STS
- Enable Kerberos for your Browser
Preparing Active Directory
To setup my test environment I needed a Active Directory service providing my test users and Kerberos support. After installing a Windows Server 2008 R2 Enterprise Edition server, I added the Active Directory feature according to a well written post, which I found on the internet.Adding users and groups
After that I created two new security groups:manager
employee
After that I added the following users to my active directory:
alice@MYDOMAIN.COM
bob@MYDOMAIN.COM
idp/idp-host.mydomain.com@MYDOMAIN.COM
I also added Alice to the group
manager
and employee
, as well as Bob to the group employee
only.Adding Service Principal Name to the IDP user
If a browser requests a Kerberos token for a webpage the Kerberos token will always be requested for the following ServicePrincipalName:HTTP/my.idp-website.com
.Therefore I need to add the matching SPN to my AD user
idp/myhost.mydomain.com@MYDOMAIN.COM
.
I my case I had some trouble with the normal account name, but with the pre-Windows2000 name it was working without issues. The pre-Windows200 account name of my idp would be
MYDOMAIN\idp_myhost
.You need to enter the following command on a console at your domain controller:
C:\> setspn -A HTTP/idp-host.mydomain.com MYDOMAIN\idp_myhost
C:\> setspn -A HTTP/idp-host MYDOMAIN\idp_myhost
If your IDP Server is accessible via multiple domain names (only DNS A-Records are considered), you should also add multiple SPNs to your IDP user.
You can use the following command to validate that you set the correct SPNs:
C:\> setspn -Q HTTP/*
You should also make sure that you have a SPN set only once! You can validate this with the following command:
C:\> setspn -X
It is very important, that you also add the correct DNS names for your
IDP in your Windows DNS Server. You cannot use an IP address directly
for the IDP server. If you do so your browser will not request a correct
Kerberos ticket for your IDP!
Extracting service private key from Kerberos
I used username/password authentication for the IDP user in the STS Kerberos token validator, which does not require to extract a keytab file from your Active Directory server. If you do use this keytab file you do not need to provide username/password instead.
The STS needs access to its own keytab file for being able to validate the Kerberos authentication of the user. Therefore we need to extract the private key to a file.
ktpass -princ idp/idp-host.mydomain.com@MYDOMAIN.COM -mapuser
MYDOMAIN\IdpMyHost -pass password -crypto All -kvno 0 -ptype KRB5_NT_PRINCIPAL
-out c:\temp\IdpMyHost.keytab
The extracted keytab file must be transfered to the server where the IDP and STS will be installed.
Installing Demo Application
Download and setup Apache Tomcat 7 as usual.
After that you must define a
fediz_config.xml
configuration file for the Fediz plugin in the conf
folder from Tomcat. You can find further steps to setup Tomcat on the Apache website.<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <FedizConfig> <contextConfig name="/fedizhelloworld"> <audienceUris> <audienceItem>urn:org:apache:cxf:fediz:fedizhelloworld</audienceItem> </audienceUris> <certificateStores> <trustManager> <keyStore file="ststrust.jks" password="storepass" type="JKS" /> </trustManager> </certificateStores> <trustedIssuers> <issuer certificateValidation="PeerTrust" /> </trustedIssuers> <maximumClockSkew>1000</maximumClockSkew> <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="federationProtocolType" version="1.0.0"> <realm>urn:org:apache:cxf:fediz:fedizhelloworld</realm> <issuer>https://localhost:9443/fediz-idp/federation</issuer> <roleDelimiter>,</roleDelimiter> <roleURI>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</roleURI> <claimTypesRequested> <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" optional="false" /> </claimTypesRequested> </protocol> </contextConfig> </FedizConfig>Now you can download the the latest version of Fediz from github. Next you need to build all Fediz dependencies with maven and copy them to the
lib/fediz
folder of your Tomcat installation. Go to cxf-fediz/plugins/tomcat
and execute the following command:mvn clean install
You must also update the
common.loader
property in conf/catalina.properties
:common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/fediz/*.jar
Next you can build the example web application. Go to
cxf-fediz/examples/simpleWebapp
and build your webapp again with maven:mvn clean install
You must then copy the war file of the example web application to your Tomcat
webapps
folder.Now you can start your relying party Tomcat container.
If you open http://localhost:8080/fedizhelloworld/ in your browser you should see a "Hello World" message.
If you go to http://localhost:8080/fedizhelloworld/secure/fedservlet you will be redirected to the IDP which we will setup next.
Installing Fediz IDP & STS
Tomcat Setup
Make sure that the JDK has unlimited security policies installed. Since we already have a running Tomcat 7 installation for the relying party we will just copy that installation and deleting thefedizhelloworld
web application from the webapps/
folder as well as the fediz_config.xml
configuration file in the conf/
folder. If we plan to run both Tomcat Server on the same machine we
must also update the server ports in the conf/server.xml
file.<Connector port="9443" protocol="org.apache.coyote.http11.Http11Protocol" maxHttpHeaderSize="65536" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" keystoreFile="idp-ssl-server.jks" keystorePass="tompass" truststoreFile="idp-ssl-server.jks" truststorePass="tompass" truststoreType="JKS" SSLVerifyClient="optional" clientAuth="want" sslProtocol="TLS" />
It is very important that you increase the default max header size from tomcat. Otherwise some of your users will get a
401 Bad Request
Error if the Kerberos token is bigger than 8kb.
You must also set
clientAuth
to want
and configure a trust-store, if you run IDP and STS in the same Tomcat container, because the STS requires x509 client authentication.
Since the IDP uses JPA (since version 1.2) to store its configuration settings, we must also download the matching JDBC driver and place the driver to our Tomcat lib folder. Next we must set the domain name or IP address of the KDC Kerberos server. This we can do best by setting a JVM parameter via CATALINA_OPTS by creating or updating the setenv.bat respectively setenv.sh in the Tomcat bin folder:
set CATALINA_OPTS=%CATALINA_OPTS% "-Djava.security.krb5.kdc=192.168.1.10 -Djava.security.krb5.realm=MYDOMAIN.COM -Djava.security.auth.login.config=file:/C:/Fediz-IDP-A/webapps/fediz-idp/WEB-INF/kerberos.jaas -Dsun.security.krb5.debug=true"
If you are planing on running your IDP/STS Tomcat container as a system service, you must modify the
service.bat
file to ensure that you set the required Kerberos JVM parameter correctly. Otherwise your Tomcat will start without these parameters and Kerberos authentication will fail.SSL Certificate
Providing a trusted SSL Certificate for the IDP helps to avoid irritating warnings from the browser when users access the IDP via a HTTPs connection. Since all computer of a Active Directory Domain share common trusted domain certificates, we can create a new webserver key at the AD which will be trusted by all participants of the domain.
The certificate is only trusted at the Internet Explorer by default. To extend this trust to Firefox as well, you need to install the domain certificate manually into the trusted issuer store of Firefox.
To do this you must define a certificate webserver policy at the AD server which allows the export of a private key. Next we need to create a new private/public key pair at the server with the common name (CN) being equal to the domain name of our IDP. After creating the certificate we need to export the key pair to a PKCS #12 file format. I like to use the KeyStore Explorer best to manage Java keystores. The KeyStore Explorer is also able to import the keypair export from the AD server. To set the correct key for the IDP Tomcat server, you need to replace the
mytomidpkey
key in the idp-ssl-server.jks
keystore.
Download or Build the IDP/STS
You can either download the IDP/STS from Apache webpage or you can build the IDP and STS again with maven. If you build your services from code, you can also update the configuration files before you build your war files. In that case you do not need to modify them later on. If you want to use Maven to build your own services execute the following command:mvn clean install -Pkerberos
After deploying the fediz-idp.war
and fediz-idp-sts.war
to tomcat, you need to update the following configuration files according to your needs.
STS Configuration
Thekerberos.jaas
file must be updated for the STS to match with our Kerberos idp principal:
idp { com.sun.security.auth.module.Krb5LoginModule required refreshKrb5Config=true storeKey=true principal="idp/idp-host.mydomain.com@MYDOMAIN.COM"; };Make sure that the
cxf-transport.xml
file imports the kerberos.xml
file, which should already be the case if you build the STS with the kerberos
Maven profile.
Most changes required to enable Kerberos Authentication and Active Directory Claim Handling needs to be configured in the kerberos.xml
file. You need to add the LDAP Claim Handler as well as the Kerberos Token Validator. If you use a kerberos keytab file for the IDP you do not need to set a callbackHandler for the kerberos token validator but the location to your keytab file instead.
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <util:list id="claimHandlerList"> <ref bean="claimsHandlerA" /> <ref bean="claimsHandlerB" /> </util:list> <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://ad-host.mydomain.com:389" /> <property name="userDn" value="CN=IDP,OU=People,DC=mydomain,DC=com" /> <property name="password" value="secretPwd" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean> <util:map id="claimsToLdapAttributeMapping"> <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role" value="memberOf" /> <entry key="http://schemas.zurich.com/security/authorization/de/2013/05/claims/role" value="memberOf" /> <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" value="givenName" /> <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" value="sn" /> <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" value="mail" /> <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country" value="c" /> </util:map> <bean id="claimsHandlerA" class="org.apache.cxf.sts.claims.LdapClaimsHandler"> <property name="ldapTemplate" ref="ldapTemplate" /> <property name="claimsLdapAttributeMapping" ref="claimsToLdapAttributeMapping" /> <property name="userNameAttribute" value="userPrincipalName" /> <property name="userBaseDN" value="OU=People,DC=mydomain,DC=com" /> <property name="realm" value="REALMA" /> </bean> <bean id="kerberosValidator" class="org.apache.ws.security.validate.KerberosTokenValidator"> <property name="contextName" value="idp"/> <property name="serviceName" value="HTTP/idp-host.mydomain.com@MYDOMAIN.COM"/> <property name="usernameServiceNameForm" value="true"/> <property name="spnego" value="true"/> <property name="callbackHandler"> <bean class="com.sun.jndi.ldap.sasl.DefaultCallbackHandler"> <constructor-arg index="0" value="idp/idp-host.mydomain.com@MYDOMAIN.COM"/> <constructor-arg index="1" value="secretPwd"/> <constructor-arg index="2" value="MYDOMAIN.COM"/> </bean> </property> </bean> <jaxws:endpoint id="transportSTSRealmAKerberos" implementor="#transportSTSProviderBean" address="/REALMA/STSServiceTransportKerberos" wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl" xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/" serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port"> <jaxws:properties> <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/> </jaxws:properties> </jaxws:endpoint> <jaxws:endpoint id="transportSTSRealmBKerberos" implementor="#transportSTSProviderBean" address="/REALMB/STSServiceTransportKerberos" wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl" xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/" serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportKerberos_Port"> <jaxws:properties> <entry key="ws-security.bst.validator" value-ref="kerberosValidator"/> </jaxws:properties> </jaxws:endpoint> </beans>
IDP Configuration
The content of thesecurity-config.xml
file must be replaced with the content of security-config-kerberos.xml
:
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <context:property-placeholder location="classpath:realm.properties"/> <context:component-scan base-package="org.apache.cxf.fediz.service.idp"/> <!-- Configure Spring Security --> <security:http auto-config="false" use-expressions="true" entry-point-ref="kerberosEntryPoint"> <security:custom-filter after="CHANNEL_FILTER" ref="stsPortFilter" /> <security:intercept-url pattern="/FederationMetadata/2007-06/FederationMetadata.xml" access="isAnonymous() or isAuthenticated()" /> <!--<security:http-basic />--> <!--<security:form-login />--> <security:custom-filter ref="kerberosAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" /> </security:http> <bean id="kerberosEntryPoint" class="org.apache.cxf.fediz.service.idp.kerberos.KerberosEntryPoint" /> <bean id="kerberosAuthenticationProcessingFilter" class="org.apache.cxf.fediz.service.idp.kerberos.KerberosAuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManager" /> </bean> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="stsAuthProvider" /> </security:authentication-manager> <bean id="stsPortFilter" class="org.apache.cxf.fediz.service.idp.STSPortFilter" /> <bean id="stsAuthProvider" class="org.apache.cxf.fediz.service.idp.STSAuthenticationProvider"> <property name="wsdlLocation" value="https://localhost:0/fediz-idp-sts/${realm.STS_URI}/STSServiceTransportKerberos?wsdl"/> <property name="wsdlEndpoint" value="TransportKerberos_Port"/> <property name="wsdlService" value="SecurityTokenService"/> <property name="appliesTo" value="urn:fediz:idp"/> <property name="tokenType" value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"/> </bean> </beans>
Enabling Kerberos Support for your browser
By default your browser will not send any Kerberos token to a normal Webpage. In IE you need to add the IDP URL to the list of trusted sides or even to local intranet sides. In Firefox you need to openabout:config
and add the IDP URL to network.negotiate-auth.delegation-uris
and network.negotiate-auth.trusted-uris
.
I found this article from Oracle most helpful to setup my browser correctly.
Troubleshooting
You can use theklist
command at your client to verify that the correct Kerberos token are used on your local machine. klist purge
will remove all cached Kerberos tokens on your computer.
You can use Wireshark to analyse your web traffic. This is especially helpful to see what kind of token Kerbeidp-ssl-server.jksros/SPNEGO your browser is sending to the IDP.
Fiddler is helpful to analyze if all the redirects from your Webapp to the IDP and back actually work as expected.
Links
- http://docs.fedoraproject.org/en-US/Fedora/html/Security_Guide/sect-Security_Guide-Single_Sign_on_SSO-Configuring_Firefox_to_use_Kerberos_for_SSO.html
- http://superuser.com/questions/5161/windows-domain-authentication-with-firefox
- http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tsec_SPNEGO_config_dc.html
- http://blogs.iis.net/brian-murphy-booth/archive/2007/03/09/the-biggest-mistake-serviceprincipalname-s.aspx
- http://www.novell.com/documentation/novellaccessmanager/adminguide/data/b9uctt5.html
- http://www.oracle.com/technetwork/articles/idm/weblogic-sso-kerberos-1619890.html
You can use the following command to test if your kerberos settings are correct and if you can get a service ticket for the defined service:
ReplyDeletekinit -S HTTP/my-web-server@EXAMPLE.COM user@EXAMPLE.COM