Ir al contenido
Otras versiones

Cargando…

Configuración de SSO

El objetivo de esta configuración es permitir que los usuarios inicien sesión en OpenKM con sus credenciales de Windows. Para ello, es necesario configurar algunos elementos, entre ellos los navegadores de los clientes.

En nuestro caso, todo el sistema se integra de la siguiente manera:

  • Active Directory en Windows Server 2008 y Windows Server 2012
  • Servidor Tomcat en una máquina Linux
  • Clientes en Windows 7 (navegadores: Internet Explorer y Firefox)

Se han utilizado las siguientes guías como punto de partida:

Se asume que hay un servidor Active Directory instalado y en funcionamiento (implementación de LDAP) donde se van a configurar todas las cuentas de usuario que se utilizarán posteriormente.

Los pasos a seguir son:

  1. Cree un objeto Computer dentro de Active Directory que corresponda al servidor Linux

    • Una vez hecho, modifique sus propiedades y active la siguiente opción:
      • Trusted for delegation: Este paso es importante porque, si no se habilita, la negociación entre clientes y servidores no será posible.
  2. El servidor debe autenticarse contra Active Directory antes de validar los tickets enviados por el cliente. Esta autenticación se realiza mediante un fichero (keytab) que asocia el servicio (servidor de aplicaciones) con un usuario de dominio. Cree un usuario de dominio. Este usuario debe utilizarse únicamente para este fin, porque si se utiliza para iniciar sesión en otro equipo, ya no podrá utilizarse para iniciar sesión en el servidor de aplicaciones. Una vez creado el usuario, deben modificarse sus propiedades para impedir el cambio de contraseña y evitar que la cuenta caduque.

  3. Genere el fichero keytab. Este fichero es una copia codificada de la clave privada de un usuario en Kerberos. La aplicación web lo utiliza como proxy de autenticación para las credenciales enviadas por el usuario. Se ejecuta el siguiente comando:

    Ventana de terminal
    C:\>  ktpass -princ HTTP/tomcat.example.com@EXAMPLE.COM -mapuser user@EXAMPLE.COM -crypto all -kvno 0 -ptype KRB5_NT_PRINCIPAL -pass * -out web.keytab

    Es importante destacar:

    • 1. tomcat.example.com@EXAMPLE.COM: Nombre completo del servidor Tomcat y su dominio.
      2. user@EXAMPLE.COM: El usuario creado anteriormente.
      3. web.keytab: El fichero donde se exporta la clave privada utilizada por el servidor Tomcat.
  4. Registre los nuevos servicios SPN. Es necesario configurar un Service Principal Name (SPN) con HTTP y un nombre de servidor; por ejemplo: tomcat.example.org, donde se está ejecutando Tomcat. Esto se utiliza con un usuario de dominio y su keytab se emplea después como credencial de servicio:

    Ventana de terminal
    C:\> setspn -A HTTP/tomcat.example.org@EXAMPLE.ORG user
    C:\> setspn -A HTTP/tomcat.example.org user
  5. Verifique que los servicios se han creado correctamente y están vinculados al usuario:

    Ventana de terminal
    C:\> setspn -l user
  6. Por último, cree los grupos que se asignarán a los usuarios y de los que se obtendrán los roles correspondientes (debería tenerlos del paso anterior de integración con AD). Se recomienda crear:

    • Una unidad organizativa (OU) llamada OpenKM
    • Dentro de la unidad organizativa anterior, cree los grupos que se utilizarán como roles
      • ROLE_USER
      • ROLE_ADMIN

Lo primero que hay que hacer es incluir el servidor de aplicaciones dentro del dominio, si no se hizo previamente. Para ello, siga la guía:
http://cerowarnings.blogspot.com.es/2011/11/how-to-linux-en-dominio-windows.html

Una cuestión a tener en cuenta es añadir la siguiente configuración al fichero /etc/hosts debido a problemas conocidos previamente:

# ldap in /etc/hosts
192.168.1.110 example.com
192.168.1.110 Schema.Configuration.example.com
192.168.1.110 Configuration.example.com
192.168.1.110 DomainDnsZones.example.com
192.168.1.110 ForestDnsZones.example.com

Instale el cliente de Kerberos:

Ventana de terminal
$ apt-get krb5-user krb5-config

Antes de iniciar la aplicación, Kerberos debe estar configurado correctamente para validar los tickets de forma adecuada. En los sistemas Linux este fichero se encuentra en “/etc/krb5.conf”.

En este fichero deben especificarse el dominio, el servidor KDC y los algoritmos permitidos. Los algoritmos más importantes son arcfour-hmac-md5 y rc4-hmac, que ofrece Microsoft Active Directory.

[libdefaults]
default_realm = EXAMPLE.COM
#these are mandatory for kerberos.
permitted_enctypes = aes128-cts rc4-hmac
default_tgs_enctypes = aes128-cts rc4-hmac
default_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.COM

Para cambiar el tipo de autenticación que se va a utilizar, es necesario modificar los dos ficheros siguientes:

  • $CATALINA_HOME/webapps/OpenKM/WEB-INF/appContext.xml:
    Cambie la siguiente línea:
<security:http access-decision-manager-ref="accessDecisionManager" access-denied-page="/unauthorized.jsp">

por

<security:http access-decision-manager-ref="accessDecisionManager" access-denied-page="/unauthorized.jsp" entry-point-ref="spnegoEntryPoint" authentication-manager-ref="authenticationManagerSpnego">

Bajo esta línea añada:

<security:custom-filter ref="spnegoAuthenticationProcessingFilter" position="BASIC_AUTH_FILTER" />

Un detalle a tener en cuenta dentro de este fichero es que, si se requiere filtrar no solo la autenticación sino también los roles, es necesario sustituir el atributo IS_AUTHENTICATED_FULLY por una lista de roles autorizados separados por comas (ROLE_USER, ROLE_ADMIN)

  • $CATALINA_HOME/openkm.xml

    Comente la línea:

<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>

Y añada lo siguiente:

<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>

Los datos de configuración importantes a tener en cuenta son:

  • ldap://server.example.com:389/dc=example,dc=com, que es la ubicación del servidor LDAP.
  • servicePrincipal, que es el servicio creado previamente en el servidor: HTTP/tomcat.example.org@EXAMPLE.COM
  • keyTabLocation: que es la ubicación en el sistema de ficheros de la máquina Linux del fichero keytab creado en el servidor Active Directory. (Es posible utilizar classpath:, pero es preferible utilizar file:)

Una vez realizadas las configuraciones anteriores, se puede iniciar el servidor Tomcat. Para que los nombres de usuario y los roles estén disponibles dentro de OpenKM, es necesario configurar LDAP. Para ello, se recomienda seguir los pasos de los parámetros de configuración de LDAP.

Para permitir la negociación automática de credenciales, también es necesario configurar los navegadores web de los clientes. Esto se detalla en:

http://docs.spring.io/spring-security-kerberos/docs/1.0.0.RC2/reference/htmlsingle/#browserspnegoconfig

  • Firefox

    1. Abra Firefox.
    2. En el campo de dirección, escriba about:config.
    3. En el campo de filtro/búsqueda, escriba negotiate.
    4. Es posible que el parámetro network.negotiate-auth.trusted-uris esté establecido con el valor por defecto https://, que puede no funcionar en su caso. Sustitúyalo por la dirección de su servidor (tomcat.example.com en nuestro ejemplo).
  • Internet Explorer:

    1. Abra Internet Explorer.
    2. Haga clic en Tools > Internet Options > pestaña Security.
    3. En la sección Local intranet, asegúrese de que su servidor es de confianza, es decir, añádalo a la lista (tomcat.example.com en nuestro ejemplo).
    4. En las opciones avanzadas: asegúrese de que la opción “Enable Integrated Windows Authentication” está habilitada
    5. Añada la dirección de su servidor (tomcat.example.com en nuestro ejemplo)
  • Chrome:

    1. Abra Chrome.
    2. Haga clic en Configuration > Show Advanced Configuration > Change proxy configuration > pestaña Security.
    3. En la sección Local intranet, asegúrese de que su servidor es de confianza, es decir, añádalo a la lista (tomcat.example.com en nuestro ejemplo).
    4. En las opciones avanzadas: asegúrese de que la opción “Enable Integrated Windows Authentication” está habilitada.
    5. Añada la dirección de su servidor (tomcat.example.com en nuestro ejemplo)

Habilitar el registro para la autenticación SSO

Sección titulada «Habilitar el registro para la autenticación SSO»

Modifique el fichero de configuración de registro y añada la línea:

<logger name="org.springframework.security" level="DEBUG" />

Comprobar la autenticación Kerberos desde la línea de comandos de Linux

Sección titulada «Comprobar la autenticación Kerberos desde la línea de comandos de Linux»

Ejecute el comando (distingue entre mayúsculas y minúsculas, y las mayúsculas son importantes):

Ventana de terminal
$ kinit user@EXAMPLE.ORG

Si todo es correcto, se le solicitará la contraseña y el inicio de sesión desde Linux se realizará con éxito. Si algo va mal, hay algún problema en la configuración de su cliente Kerberos de Linux (krb5.conf).

La mayoría de los problemas que hemos encontrado están causados por una creación incorrecta del fichero web.keytab. Si obtiene errores como:

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 more
Caused 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 more
Caused 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 more
Caused 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 more
Caused 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 more

Probablemente su web.keytab es incorrecto. Asegúrese de haber ejecutado el comando “ktpass” antes de ejecutar los comandos “setspn”.