SSO Configuration
Esta página aún no está disponible en tu idioma.
The aim of this configuration is to allow users to login into OpenKM with their Windows credentials. To do it, it is necesary to configure some stuff, including client’s browsers.
In our case the whole system is integrated by:
- Active Directory in Windows 2008 and Windows 2012 server
- Tomcat server in a Linux machine
- Client on Windows 7 (Browsers Internet Explorer and Firefox)
The following guides have been used as a start point:
- http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=spnego-spring
- http://wiki.openkm.com/index.php/Active_Directory_-_OpenKM_6.2
- LDAP configuration parameters
- http://projects.spring.io/spring-security-kerberos/
- http://docs.spring.io/spring-security-kerberos/docs/1.0.0.RC2/reference/htmlsingle/
Active Directory
Section titled “Active Directory”It is supposed that there is an Active Directory server installed and running (LDAP implementation) where it is going to be configured all the user accounts that will be used later.
The steps to follow are:
-
Create a Computer object inside Active Directory that will correspond to the Linux server
- Once done, modify its properties and activate the following option:
- Trusted for delegation: This step is important because, if not enabled, negotiation between clients and servers won’t be possible.
- Once done, modify its properties and activate the following option:
-
The server must authenticate against Active Directory before validating the tickets sent by the client. This authentication is performed using a file (keytab) that map the service (application server) with a domain user. Create a domain user. This user must be used only and exclusively for this purpose because if this user is used to log into another computer, it won’t be able to be used to log on the application server. Once created the user, its properties are modified to not allow the modification of the password and the non expiration of the account.
-
Generate keytab file. This file is an encoded copy of the private key of an user in Kerberos. It is used by the application web as an authentication proxy of the credentials sent by the user. The following command is executed:
Terminal window C:\> ktpass -princ HTTP/tomcat.example.com@EXAMPLE.COM -mapuser user@EXAMAPLE.COM -crypto all -kvno 0 -ptype KRB5_NT_PRINCIPAL -pass * -out web.keytabIt is important to highlight :
- 1. tomcat.example.com@EXAMPLE.COM: Full name of the Tomcat server and its domain.
2. user@EXAMAPLE.COM: The user created previously.
3. web.keytab: The file where the private key that will be used by the Tomcat server is exported.
- 1. tomcat.example.com@EXAMPLE.COM: Full name of the Tomcat server and its domain.
-
Register new SPN services. A Service Principal Name (SPN) needs to be setup with HTTP and a server name: in example: tomcat.example.org where Tomcat is running. This is used with domain user and its keytab is then used as a service credential:
Terminal window C:\> setspn -A HTTP/tomcat.example.org@EXAMPLE.ORG userC:\> setspn -A HTTP/tomcat.example.org user -
Verify services has been correctly created and linked to the user:
Terminal window C:\> setspn -l user -
Finally create the groups that will be assigned to the users and which the corresponding roles will be obtainined from ( You should have it from previous AD integration step ). It is recomended to create:
- An Organization Unit (OU) with name OpenKM
- Inside the previous Organization Unit , create the groups that will be used as roles
- ROLE_USER
- ROLE_ADMIN
Linux Machine
Section titled “Linux Machine”The first thing to do is to include the application server inside the domain, if it was not done previously. To do it follow the guide:
http://cerowarnings.blogspot.com.es/2011/11/how-to-linux-en-dominio-windows.html
One thing to consider is to add the following configuration to the file /etc/host due to previously known problems:
# ldap in /etc/hosts192.168.1.110 example.com192.168.1.110 Schema.Configuration.example.com192.168.1.110 Configuration.example.com192.168.1.110 DomainDnsZones.example.com192.168.1.110 ForestDnsZones.example.comKerberos configuration file
Section titled “Kerberos configuration file”Install kerberos client:
$ apt-get krb5-user krb5-configBefore starting the application Kerberos must be configured properly to validate tickets correctly. In Linux systems this file is located at “/etc/krb5.conf”.
In this file Domain, KDC server and allowed algorithms must be specified. The most importans algorithms are arcfour-hmac-md5 and rc4-hmac which Microsoft Active Directory offers.
[libdefaults]default_realm = EXAMPLE.COM#these are mandatory for kerberos.permitted_enctypes = aes128-cts rc4-hmacdefault_tgs_enctypes = aes128-cts rc4-hmacdefault_tkt_enctypes = aes128-cts rc4-hmac[realms]EXAMPLE.COM = { kdc = SERVER.example.com admin_server = SERVER.example.com default_domain = EXAMPLE.COM}[domain_realm]example.com = EXAMPLE.COM.example.com = EXAMPLE.COMConfiguration files
Section titled “Configuration files”To change the authentication type to use it is necessary to modify the following two files:
- $CATALINA_HOME/webapps/OpenKM/WEB-INF/appContext.xml:
Change the following line:
<security:http access-decision-manager-ref="accessDecisionManager" access-denied-page="/unauthorized.jsp">to
<security:http access-decision-manager-ref="accessDecisionManager" access-denied-page="/unauthorized.jsp" entry-point-ref="spnegoEntryPoint" authentication-manager-ref="authenticationManagerSpnego">Under this line add:
<security:custom-filter ref="spnegoAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />A detail to take into account inside this file, is that if it is required to filter the access not only but the authentication but the roles too, it is needed to replace the attribute IS_AUTHENTICATED_FULLY to an authorize role list separated by comas (ROLE_USER, ROLE_ADMIN)
-
$CATALINA_HOME/OpenKM.xml
Comment the line:
<security:authentication-manager alias="authenticationManager"> <security:authentication-provider> <security:password-encoder hash="md5"/> <security:jdbc-user-service data-source-ref="dataSource" users-by-username-query="select usr_id, usr_password, 1 from OKM_USER where usr_id=? and usr_active='T'" authorities-by-username-query="select ur_user, ur_role from OKM_USER_ROLE where ur_user=?"/> </security:authentication-provider> </security:authentication-manager>And add the following:
<beans:bean id="spnegoEntryPoint" class="org.springframework.security.kerberos.web.authentication.SpnegoEntryPoint"> <beans:constructor-arg value="/login" /></beans:bean> <beans:bean id="kerberosAuthenticationProvider" class="org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider"> <beans:property name="userDetailsService" ref="ldapUserDetailsService" /> <beans:property name="kerberosClient"> <beans:bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient"> <beans:property name="debug" value="true"/> </beans:bean> </beans:property></beans:bean> <!--beans:bean id="kerberosServiceAuthenticationProvider" class="org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider"--><beans:bean id="kerberosServiceAuthenticationProvider" class="com.openkm.spring.OKMKerberosServiceAuthenticationProvider"> <beans:property name="ticketValidator"> <beans:bean class="org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator"> <beans:property name="servicePrincipal" value="HTTP/tomcat.example.com@EXAMPLE.COM" /> <beans:property name="keyTabLocation" value="file:/path/to/web.keytab" /> <beans:property name="debug" value="true" /> </beans:bean> </beans:property> <beans:property name="userDetailsService" ref="ldapUserDetailsService" /></beans:bean><!-- Ticket security manager --><security:authentication-manager id="authenticationManagerSpnego"> <security:authentication-provider ref="kerberosAuthenticationProvider" /> <security:authentication-provider ref="kerberosServiceAuthenticationProvider" /></security:authentication-manager><beans:bean id="spnegoAuthenticationProcessingFilter" class="org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter"> <beans:property name="authenticationManager" ref="authenticationManagerSpnego" /></beans:bean> <beans:bean id="authorizationContextSource" class="org.springframework.security.kerberos.client.KerberosLdapContextSource"> <beans:constructor-arg value="ldap://server.example.com:389/dc=example,dc=com" /> <beans:property name="loginConfig" ref="LoginConfig"/></beans:bean><beans:bean id="LoginConfig" class="org.springframework.security.kerberos.client.config.SunJaasKrb5LoginConfig" init-method="afterPropertiesSet"> <beans:property name="servicePrincipal" value="HTTP/tomcat.example.com@EXAMPLE.COM"/> <beans:property name="keyTabLocation" value="file:/path/to/web.keytab" /> <beans:property name="useTicketCache" value="false" /> <beans:property name="isInitiator" value="true" /> <beans:property name="debug" value="true" /></beans:bean><beans:bean id="ldapUserDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService"> <beans:constructor-arg ref="FilterBasedLdapUserSearch" /> <beans:constructor-arg ref="defaultLdapAuthoritiesPopulator" /> <beans:property name="UserDetailsMapper" ref="UserDetailsMapper" /></beans:bean><beans:bean id="FilterBasedLdapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch"> <beans:constructor-arg value="" /> <!--beans:constructor-arg value="dc=example,dc=com" /--> <beans:constructor-arg value="(| (userPrincipalName={0}) (sAMAccountName={0}))" /> <beans:constructor-arg ref="authorizationContextSource" /></beans:bean><beans:bean id="defaultLdapAuthoritiesPopulator" class="com.openkm.spring.OKMLdapAuthoritiesPopulator"/><beans:bean id="UserDetailsMapper" class="org.springframework.security.ldap.userdetails.LdapUserDetailsMapper"/><beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider"> <beans:constructor-arg> <beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator"> <beans:constructor-arg ref="authorizationContextSource"/> <beans:property name="userSearch" ref="FilterBasedLdapUserSearch"/> </beans:bean> </beans:constructor-arg> <beans:constructor-arg ref="defaultLdapAuthoritiesPopulator" /></beans:bean><!-- Alternative Ldap security manager --><security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="ldapAuthProvider" /></security:authentication-manager>The important configuration data to take into account is:
- ldap://server.example.com:389/dc=example,dc=com” that is the location of the ldap server.
- servicePrincipal that is the service previusly created at the server: HTTP/tomcat.example.org@EXAMPLE.COM
- keyTabLocation: that is the location inside the file system of the linux machine of the keytab file created in the Active directory server. ( It is possible to use classpath: but is preferable use file:)
Configure LDAP in OpenKM
Section titled “Configure LDAP in OpenKM”Once done the previously configurations, the Tomcat server can be start up. To allow user name and role to be available inside OpenKM, it is necessary to configurate LDAP. To do it, it’s recomended to follow the steps of LDAP configuration parameters.
Client browsers:
Section titled “Client browsers:”To allow the automatic credentials negotiation, it is also necessary to configure the client web browsers. This is detailed at:
-
Firefox
- Open Firefox.
- At address field, type about:config.
- In filter/search, type negotiate.
- Parameter network.negotiate-auth.trusted-uris may be set to default https:// which doesn’t work for you. Replace this with your server address (tomcat.example.com in our example).
-
Internet Explorer:
- Open Internet Explorer.
- Click Tools > Intenet Options > Security tab.
- In Local intranet section make sure your server is trusted by i.e. adding it into a list (tomcat.example.com in our example)..
- In advanced options: check the option “Enable Integrated Windows Authentication” is enabled
- Add your server address (tomcat.example.com in our example)
-
Chrome:
- Open Chrome.
- Click Configuration> Show Advanced Configuration > Change proxy configuration > Security tab.
- In Local intranet section make sure your server is trusted by i.e. adding it into a list (tomcat.example.com in our example)..
- In advanced options: check the option “Enable Integrated Windows Authentication” is enabled.
- Add your server address (tomcat.example.com in our example)
Throubleshootings
Section titled “Throubleshootings”Enable log for SSO authentication
Section titled “Enable log for SSO authentication”Modify the log configuration file and add the line:
<logger name="org.springframework.security" level="DEBUG" />Check kerberos authentication from linux command line
Section titled “Check kerberos authentication from linux command line”Execute the command ( it’s case sensitive and uppercase is important ) :
$ kinit user@EXAMPLE.ORGIf all is right, you will be inquired for setting the password and the login from linux is make. If it’s going wrong you have something wrong in your kerberos linux client configuration ( krb5.conf ).
Listing keys
Section titled “Listing keys ”Almost problems we have found, comes with bad we.keytab creation file. If you get errors like:
rg.springframework.ldap.AuthenticationException: GSSAPI; nested exception is javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))]] at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:182) at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:285) at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:119) at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:138) at org.springframework.ldap.core.LdapTemplate.executeReadOnly(LdapTemplate.java:791) at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntry(SpringSecurityLdapTemplate.java:194) at org.springframework.security.ldap.search.FilterBasedLdapUserSearch.searchForUser(FilterBasedLdapUserSearch.java:116) at org.springframework.security.ldap.userdetails.LdapUserDetailsService.loadUserByUsername(LdapUserDetailsService.java:38) at com.openkm.spring.OKMKerberosServiceAuthenticationProvider.authenticate(OKMKerberosServiceAuthenticationProvider.java:64) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) at org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:145) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)Caused by: javax.naming.AuthenticationException: GSSAPI [Root exception is javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))]] at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(LdapSasl.java:168) at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:235) at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2740) at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:316) at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:193) at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:211) at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:154) at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:84) at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:684) at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307) at javax.naming.InitialContext.init(InitialContext.java:242) at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:153) at org.springframework.ldap.core.support.LdapContextSource.getDirContextInstance(LdapContextSource.java:43) at org.springframework.security.kerberos.client.KerberosLdapContextSource.access$001(KerberosLdapContextSource.java:66) at org.springframework.security.kerberos.client.KerberosLdapContextSource$1.run(KerberosLdapContextSource.java:110) at org.springframework.security.kerberos.client.KerberosLdapContextSource$1.run(KerberosLdapContextSource.java:105) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:356) at org.springframework.security.kerberos.client.KerberosLdapContextSource.getDirContextInstance(KerberosLdapContextSource.java:105) at org.springframework.ldap.core.support.AbstractContextSource.createContext(AbstractContextSource.java:273) ... 39 moreCaused by: javax.security.sasl.SaslException: GSS initiate failed [Caused by GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7))] at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:212) at com.sun.jndi.ldap.sasl.LdapSasl.saslBind(LdapSasl.java:123) ... 58 moreCaused by: GSSException: No valid credentials provided (Mechanism level: Server not found in Kerberos database (7)) at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:710) at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:248) at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:179) at com.sun.security.sasl.gsskerb.GssKrb5Client.evaluateChallenge(GssKrb5Client.java:193) ... 59 moreCaused by: KrbException: Server not found in Kerberos database (7) at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:70) at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:192) at sun.security.krb5.KrbTgsReq.sendAndGetCreds(KrbTgsReq.java:203) at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:309) at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:115) at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:456) at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:641) ... 62 moreCaused by: KrbException: Identifier doesn't match expected value (906) at sun.security.krb5.internal.KDCRep.init(KDCRep.java:143) at sun.security.krb5.internal.TGSRep.init(TGSRep.java:66) at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:61) at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:55) ... 68 moreProbably your web.keytab is wrong. Ensure you have executed “ktpass” command before executing the “setspn” ones.