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, incluidos los navegadores de los clientes. 

En nuestro caso, el sistema completo está integrado por:

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

Las siguientes guías se han utilizado como punto de partida:

Se supone que existe un servidor de 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 Equipo (Computer) dentro de Active Directory que corresponderá 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 está habilitado, no será posible la negociación entre clientes y servidores.
  2. El servidor debe autenticarse contra Active Directory antes de validar los tickets enviados por el cliente. Esta autenticación se realiza mediante un archivo (keytab) que asocia el servicio (servidor de aplicaciones) con un usuario del dominio. Cree un usuario de dominio. Este usuario debe utilizarse única y exclusivamente para este fin, porque si se utiliza para iniciar sesión en otro equipo, no podrá utilizarse para iniciar sesión en el servidor de aplicaciones. Una vez creado el usuario, se modifican sus propiedades para no permitir la modificación de la contraseña y para que la cuenta no caduque.

  3. Genere el archivo keytab. Este archivo es una copia codificada de la clave privada de un usuario en Kerberos. La aplicación web lo utiliza como proxy de autenticación de 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@EXAMAPLE.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@EXAMAPLE.COM: el usuario creado anteriormente.
      3. web.keytab: el archivo donde se exporta la clave privada que utilizará el servidor Tomcat.
  4. Registre los nuevos servicios SPN. Hay que configurar un Service Principal Name (SPN) con HTTP y un nombre de servidor; por ejemplo: tomcat.example.org, donde se ejecuta Tomcat. Se utiliza con el 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) con el nombre 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 en el dominio, si no se ha hecho previamente. Para ello, siga la guía:
http://cerowarnings.blogspot.com.es/2011/11/how-to-linux-en-dominio-windows.html

Un aspecto a tener en cuenta es añadir la siguiente configuración al archivo /etc/host 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 correctamente configurado para validar los tickets. En los sistemas Linux este archivo se encuentra en “/etc/krb5.conf”.

En este archivo 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 utiliza, es necesario modificar los dos archivos 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 en este archivo es que, si se necesita filtrar el acceso no solo por la autenticación sino también por 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: es la ubicación, dentro del sistema de archivos de la máquina linux, del archivo keytab creado en el servidor de Active Directory. (Es posible utilizar classpath:, pero es preferible utilizar file:)

Una vez realizadas las configuraciones anteriores, puede iniciarse el servidor Tomcat. Para que el nombre de usuario y el rol estén disponibles dentro de OpenKM, es necesario configurar LDAP. Para ello, se recomienda seguir los pasos de LDAP configuration parameters.

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 filtro/búsqueda, escriba negotiate.
    4. El parámetro network.negotiate-auth.trusted-uris puede estar establecido por defecto en https://, que no le funcionará. 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 > Intenet Options > pestaña Security.
    3. En la sección Local intranet, asegúrese de que su servidor es de confianza, por ejemplo añadiéndolo a una lista (tomcat.example.com en nuestro ejemplo).
    4. En las opciones avanzadas: compruebe 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, por ejemplo añadiéndolo a una lista (tomcat.example.com en nuestro ejemplo).
    4. En las opciones avanzadas: compruebe 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 archivo 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 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 se realizará el inicio de sesión desde linux. 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 proceden de una mala creación del archivo 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 de “setspn”.