Java EE Security API
La especificación Java™ EE Security API 1.0 define un conjunto de anotaciones relacionadas con la seguridad que puede utilizar para la autenticación. La especificación también define un conjunto común de API que puede utilizar para una seguridad programática.
La especificación Java EE Security API 1.0 amplía las prestaciones de seguridad de aplicaciones autocontenidas para portar entre distintos servidores de aplicaciones y utiliza conceptos de programación modernos como, por ejemplo, Expression Language (EL) y Contexts and Dependency Injection (CDI). La siguiente lista contiene información específica de Liberty para apoyar la especificación.
appSecurity-3.0
La característica appSecurity-3.0 proporciona la prestación básica para la especificación Java EE Security API 1.0 (especificación JSR 375). Esta característica incluye las características
el-3.0 y cdi-2.0. Si desea configurar la anotación DatabaseIdentityStore, configure una de las características jdbc-4.x. Las
características javaee-8.0 y webProfile-8.0 incluyen todas las
características necesarias.
La función " appSecurity-3.0 " admite la especificación en Liberty. Esta característica soporta la API SecurityContext y todas las anotaciones definidas en la especificación. Para validar las credenciales y recopila información de grupos, la especificación incluye soporte para mecanismos de autenticación que usan anotaciones como, por ejemplo, BASIC, FORM y CustomFORM, así como Lightweight Directory Access Protocol (LDAP) y almacenes de identidad en base de datos. La característica
appSecurity-3.0 también especifica un conjunto común de las API en la clase
SecurityContext para realizar comprobaciones de seguridad programáticas. El perfil Liberty proporciona implementaciones de bean CDI para todas las anotaciones de la especificación. Además,
las aplicaciones pueden proporcionar sus propias implementaciones de bean CDI personalizadas
para dichas anotaciones.
LDAPIdentityStore
Puedes utilizar las utilidades de contraseña de Liberty para encriptar o codificar la contraseña del atributo ' bindDNPassword '. Para obtener más información sobre el cifrado de contraseñas con el mandato securityUtility , consulte MandatosecurityUtility.
DataBaseIdentityStore
El almacén de identidades en base de datos requiere una configuración de origen de datos para proporcionar la información de base de datos. El elemento dataSourceLookup de la anotación DatabaseIdentityStore hace referencia al origen de datos definido en la configuración de Liberty , como el archivo server.xml , o en una anotación Datasource . Además, defina la biblioteca del controlador JDBC para el tipo de base de datos en la configuración de Liberty .
Puede configurar un origen de datos de varias maneras. Para obtener más información sobre cómo definir un alias de autenticación en el origen de datos, consulte Configuración de alias de autenticación para Liberty. Si el origen de datos utiliza un alias de autenticación para definir el usuario y la contraseña para el origen de datos, el parámetro
datasourceLookup en la anotación DatabaseIdentityStore debe ser una consulta JNDI indirecta del origen de datos para encontrar los recursos adicionales. Por ejemplo, la búsqueda JNDI indirecta que se define en el parámetro datasourceLookup de la anotación DatabaseIdentityStore sería '
java:comp/env/jdbc/MyDatasource.
Autorización
Elija cómo configurar la autorización para su aplicación en función de sus requisitos.
- Configure la autorización para utilizar la correlación automática de roles con grupos:
- No configure ninguna tabla de autorización ni enlaces de rol en el elemento
application-bnden los archivos ibm-application-bnd.xmi, ibm-application-bnd.xml o server.xml. - Asegúrese de que el nombre de grupo devuelto por el almacén de identidades sea el mismo que el nombre de rol.
- Cuando se utiliza la anotación
LDAPIdentityStore, el nombre del grupo corresponde al atributo groupNameAttribute de la anotación. Por ejemplo, suponga que existe el siguiente objeto de grupo LDAP:
La anotación LdapIdnetityStore devuelve group1 como nombre de grupo cuando el valor del atributo groupNameAttribute se establece en cn. Por lo tanto, el nombre de rol debe configurarse como group1.cn=group1, o=mycompany, c=us
- Cuando se utiliza la anotación
- No configure ninguna tabla de autorización ni enlaces de rol en el elemento
- Especifique un conjunto de usuarios o grupos para la autoridad de autorización:
- Configure los enlaces de rol en la entrada
application-bndpara dicha aplicación. - Se puede configurar de diferentes maneras en función de las configuraciones de almacén de identidades del servidor.Cuando se utiliza la anotación LDAPIdentityStore, el nombre del grupo corresponde al atributo groupNameAttribute de la anotación. Este nombre debe corresponder al ID de acceso del atributo de grupo en el rol de seguridad. Por ejemplo, suponga que el siguiente objeto de grupo existe:
La anotación LdapIdnetityStore devuelvecn=group1, o=mycompany, c=uscn=group1, o=mycompany, c=uscomo nombre de grupo cuando el valor del atributo groupNameAttribute se establece en dn. Por lo tanto, el access-id en el elemento application-bnd debe establecerse en cn=group1, o=myCompany, c=us.
- Configure los enlaces de rol en la entrada
Consulte los ejemplos siguientes para configurar enlaces de rol de diferentes formas:
- En los ejemplos siguientes, los campos access-id y name
son necesarios. El formato completo del campo access-id
es
user:realmName/userUniqueIDpara usuarios ygroup:realmName/groupUniqueIDpara grupos. LosuniqueIDsde usuario y grupo corresponden a la información que devuelven los proveedores de identidad de aplicación.Por ejemplo, cuando se utiliza la anotación
LDAPIdentityStore,userUniqueIDes el nombre distinguido (DN) para el usuario ygroupUniqueIDse basa en el valorgroupNameAttributede la anotaciónLDAPIdentityStore. Estos valores también se corresponden con los métodosgetCallerUniqueIDygetCallerGroupsen el objetoCredentialValidationResultdevuelto por el almacén de identidades de método de validación.realmNamecorresponde alIdentityStoreIDdel almacén de identidades que se utiliza. - Si una aplicación utiliza sólo un almacén de identidades, puede configurar la
entrada
application-bndcomo se muestra en el ejemplo siguiente. No es necesario proporcionarrealmNameoIdentityStoreIDporque sólo se configura un almacén de identidades:<application type="war" id="sample" name="sample" location="sample.war"> <application-bnd> <security-role name="role1"> <user name="bob" access-id="cn=Bob Smith, o=myCompany, c=us" /> <group name="group1" access-id="cn=group1, o=myCompany, c=us" /> </security-role> </application-bnd> </application> - Si una aplicación utiliza varios almacenes de identidades, configure los correspondientes
realmNameoIdentityStoreIDdonde existan el usuario y el grupo.En el ejemplo siguiente,
ldapHostName:636es elIdentityStoreIDdevuelto por el almacén de identidades LDAP. Cuando se utiliza el almacén de identidades de base de datos,IdentityStoreIDes el nombredataSourceLookupque se utiliza en la base de datos, que es el nombre JNDI completo del origen de datos.realmNameyIdentityStoreIDse usan para distinguir usuarios y grupos entre distintos almacenes de identidades. Cuando use sus propios almacenes de identidades personalizados, haga que los valores coincidan con los correspondientes identificadores del almacén de identidades.- Ejemplo de almacén de identidades LDAP:
<application type="war" id="sample" name="sample" location="sample.war"> <application-bnd> <security-role name="role1"> <user name="bob" access-id="ldapHostName:636/cn=Bob Smith, o=myCompany, c=us" /> <group name="group1" access-id="ldapHostName:636/cn=group1,o=myCompany,c=us" /> </security-role> </application-bnd> </application> - Ejemplo de almacén de identidades de base de datos:
<application type="war" id="sample" name="sample" location="sample.war"> <application-bnd> <security-role name="role1"> <user name="bob" access-id="jdbc/myDataSource/fullNameofBob" /> <group name="group1" access-id="jdbc/myDataSource/fullGroupNameofGroup1" /> </security-role> </application-bnd> </application>
- Ejemplo de almacén de identidades LDAP:
- Además, el servidor soporta el formato ampliado actual para especificar
access-idpara el usuario y el grupo con la información derealmNameyuniqueID. Utilice el formato ampliado para configurar explícitamente el archivoaccess-idcompleto.- Ejemplo de almacén de identidades LDAP:
<application type="war" id="sample" name="sample" location="sample.war"> <application-bnd> <security-role name="role1"> <user name="bob" access-id="user:ldapHostName:636/cn=Bob Smith, o=myCompany, c=us" /> <group name="group1" access-id="group:ldapHostName:636/cn=group1, o=myCompany, c=us" /> </security-role> </application-bnd> </application> - Ejemplo de almacén de identidades de base de datos:
<application type="war" id="sample" name="sample" location="sample.war"> <application-bnd> <security-role name="role1"> <user name="bob" access-id="user:jdbc/myDataSource/fullNameofBob" /> <group name="group1" access-id="group:jdbc/myDataSource/fullGroupNameofGroup1" /> </security-role> </application-bnd> </application>
- Ejemplo de almacén de identidades LDAP:
EAR file
- Si algún módulo EJB forma parte de la aplicación, utilice la configuración del registro de usuarios en el archivo server.xml para todos los módulos de dicha aplicación en lugar de utilizar almacenes de identidad.
- Si es necesario configurar almacenes de identidad para los módulos web, utilice los mismos almacenes de identidad para todos los módulos web. Si el archivo EAR también contiene módulos EJB, el registro de usuarios que está configurado en el archivo server.xml debe coincidir con los almacenes de identidad configurados. La información que debe coincidir incluye el usuario y grupo, y el nombre de reino del registro de usuarios para el ID de almacén de identidades.
- Si los módulos se comunican entre sí, configure los ID de acceso completo tal como se especifica en la sección de autorización cuando se da una de estas condiciones:
- Los módulos de la aplicación contienen almacenes de identidad diferentes.
- El registro de usuarios del archivo server.xml no coincide con los almacenes de identidad.
Altere temporalmente el mecanismo o método de autenticación proporcionado por la aplicación.
- Configure la alteración temporal para utilizar el mecanismo de autenticación
básica.
Si no se especifica el atributo basicAuthenticationMechanismRealmName, se utiliza el valor de defaultRealm.<webAppSecurity overrideHttpAuthMethod="BASIC" basicAuthenticationMechanismRealmName="myRealm" /> - Configure la alteración temporal para utilizar el mecanismo de autenticación de
formulario.Especifique la página de formulario de inicio de sesión y la página de error de inicio de sesión. Estas dos páginas deben formar parte de un archivo WAR independiente.
- Especifique la raíz de contexto para las páginas de inicio de sesión utilizando el elemento contextRootForFormAuthenticationMechanism.
<webAppSecurity loginFormURL="/global/login/globalLogin.jsp" loginErrorURL="/global/login/globalLoginError.jsp" overrideHttpAuthMethod="FORM" contextRootForFormAuthenticationMechanism="/global/login" /> <application type="war" context-root="/global/login" id="globalLogin" name="globalLogin" location="globalLogin.war"/>
- Especifique la raíz de contexto para las páginas de inicio de sesión utilizando el elemento contextRootForFormAuthenticationMechanism.
- Configure la alteración temporal para que utilice el certificado de cliente.Puede utilizar un certificado de cliente para la autenticación de todas las aplicaciones estableciendo el método overideHttpAuthMethod en CLIENT_CERT:
<webAppSecurity overrideHttpAuthMethod="CLIENT_CERT"/>Si la autenticación de certificado de cliente falla, puede configurar la migración tras error a un método de autenticación diferente especificando el elemento allowAuthenticationFailOverToAuthMethod. Los siguientes valores son aceptables para el elemento allowAuthenticationFailOverToAuthMethod:- BASIC: se utiliza la autenticación básica.Ejemplo de una migración tras error al inicio de sesión básico:
<webAppSecurity overrideHttpAuthMethod="CLIENT_CERT" allowAuthenticationFailOverToAuthMethod="BASIC"/> - FORM: se utiliza el inicio de sesión de formulario. Cuando el valor se establece en FORM, asegúrese de que se establecen los atributos loginFormURL y loginErrorURL.
Ejemplo de una migración tras error al inicio de sesión de formulario:
Especifique los URL loginForm y loginError y el archivo .war que empaquete estos archivos:<webAppSecurity overrideHttpAuthMethod="CLIENT_CERT" allowAuthenticationFailOverToAuthMethod="FORM" loginFormURL="globalLogin/globalLogin.jsp" loginErrorURL="globalLogin/globalLoginError.jsp"/> <application type="war" id="globalLogin" name="globalLogin" location="globalLogin.war"/> - APP_DEFINED: El método de inicio de sesión que se utiliza es el que se configura con la aplicación en el archivo web.xml o en la anotación.
Ejemplo de una migración tras error para el método de autenticación definido en la aplicación utilizando el valor APP_DEFINED:
<webAppSecurity overrideHttpAuthMethod="CLIENT_CERT" allowAuthenticationFailOverToAuthMethod="APP_DEFINED"/>
Cuando utilice la autenticación de cliente, establezca el atributo clientAuthentication o clientAuthenticationSupported del elemento SSL en true para que el cliente envíe el certificado.
- BASIC: se utiliza la autenticación básica.
Cosas que se deben tener en cuenta al implementar un mecanismo de autenticación HTTP personalizado o un almacén de identidades.
- Anote la interfaz HttpAuthenticationMechanism personalizada de modo que utilice la interfaz RememberMeIdentityStore que ha implementado. Al implementar la interfaz HttpAuthenticationMechanism personalizada, tendrá el inicio de sesión único para todo el entorno de modo que cada inicio de sesión subsiguiente para un usuario pueda utilizar la información en el cookie RememberMe y evitar la necesidad de iniciar la sesión cada vez.
- No utilice el cookie RememberMe y la anotación AutoApplySession porque tienen objetivos parecidos y si se utilizan los dos puede ocasionar un comportamiento de autorización incoherente.
- Si ha proporcionado su propia implementación IdentityStore que establece el ID en la clase CredentialValidationResult y ha anotado la implementación HttpAuthenticationMechanism personalizada con la anotación RememberMe, asegúrese de que el nombre de reino no se ha establecido en el campo access-id del enlace de rol. Desea asegurarse de que el nombre de reino no se ha establecido de esta forma porque el ID IdentityStore se utiliza como reino para la autorización, pero cuando se procesa el cookie RememberMe, el ID IdentityStore no se retiene.
- Cree la clase CredentialValidationResult con el ID IdentityStore para que el ID pueda utilizarse como nombre de reino.
Implementación de un hash de contraseña personalizado para un almacén de identidades de base de datos
Se proporciona una implementación de PasswordHash predeterminada para un almacén de identidades utilizando una base de datos. PasswordHash es necesario para validar las contraseñas de usuario en la base de datos. Para proporcionar una implementación personalizada para PasswordHash, implemente javax.security.enterprise.identitystore.PasswordHash y hágalo disponible com un bean CDI en una biblioteca compartida.
- Desarrolle una implementación de javax.security.enterprise.identitystore.PasswordHash. El ejemplo siguiente
muestra un hash de contraseña ficticio de ejemplo:
package com.ibm.ws.security.pwdhash.test; import javax.security.enterprise.identitystore.PasswordHash; /** * Test PasswordHash sample for DatabaseIdentityStore. For testing purposes only. */ public class TestHash implements PasswordHash { public TestHash() { System.out.println("Init TestHash"); } @Override public boolean verify(char[] incomingPwd, String existingPwd) { System.out.println("TestHash is for testing purposes only."); String pwd = String.valueOf(incomingPwd) + "_DUMMY_HASH"; if (pwd.equals(existingPwd)) { return true; } return false; } @Override public String generate(char[] pwdToHash) { return String.valueOf(pwdToHash) + "_DUMMY_HASH"; } } - Empaquete la implementación de PasswordHash en un jar y haga disponible la clase PasswordHash como un bean
CDI. Hay varias maneras de marcar la clase como bean.
- Una opción es añadir un archivo beans.xml con bbean-discovery-mode=all a la carpeta META-INF del archivo jar. Lo siguiente es un ejemplo de archivo beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_2.xsd" bean-discovery-mode="all" version="1.1"> </beans> - Otra opción es añadir la anotación @dependiente a la clase PasswordHash
package com.ibm.ws.security.pwdhash.test; import javax.enterprise.context.Dependent; import javax.security.enterprise.identitystore.PasswordHash; /** * Test PasswordHash sample for DatabaseIdentityStore. For testing purposes only. */ @Dependent public class TestHash implements PasswordHash { ...
- Una opción es añadir un archivo beans.xml con bbean-discovery-mode=all a la carpeta META-INF del archivo jar. Lo siguiente es un ejemplo de archivo beans.xml
- Añada el jar de implementación de PasswordHash como un elemento library a server.xml, donde el atributo dir apunta a la ubicación del archivo JAR. A continuación se muestra un ejemplo de la adición de un
elemento library
<library id="CustomHashLib" fat.modify="true"> <fileset dir="${server.config.dir}" includes="CustomPasswordHash.jar"/> </library> - Añada la referencia commonLibraryRef a la aplicación IdentityStore de la base de datos en server.xml. A continuación se muestra un ejemplo de la adición de un elemento
classloader a una aplicación.
<application type="war" id="DatabaseAnnotatedCustomHashServlet" name="DatabaseAnnotatedCustomHashServlet" location="DatabaseAnnotatedCustomHash.war"> <application-bnd> <security-role name="javaeesec_basic"> <user name="blue1" access-id="user:java:comp/DefaultDataSource/blue1" /> </application-bnd> ... <classloader commonLibraryRef="CustomHashLib" /> </application> - La propiedad hashAlgorithm en la anotación DatabaseIdentityStoreDefinition
debe coincidir con la clase que se proporciona en el jar. A continuación se muestra un ejemplo de la anotación
DatabaseIdentityStoreDefinition
@DatabaseIdentityStoreDefinition( callerQuery = "select password from callers where name = ?", groupsQuery = "select group_name from caller_groups where caller_name = ?", hashAlgorithm = com.ibm.ws.security.pwdhash.test.TestHash.class) - Utilice el mismo algoritmo hash personalizado para generar contraseñas que están almacenadas en la base de datos a la que se accede mediante la base de datos IdentityStore.
Cifrado de la contraseña para usuarios del almacén de identidades de base de datos utilizando el proveedor hash de contraseña predeterminado
Instance<? extends PasswordHash> instance = CDI.current().select(Pbkdf2PasswordHash.class);
PasswordHash passwordHash = instance.get();
passwordHash.initialize(..)
password.generate(...)Utilizar la señal LTPA para inicio de sesión único (SSO)
La Security API Java EE 1.0 (JSR 375) admite la interfaz RememberMeIdentityStore. Un proveedor JSR 375 puede implementar esta interfaz de manera que la información del usuario se recuerde después de la autenticación inicial. El cookie que genera la implementación RememberMeIdentityStore puede utilizarse para conseguir el inicio de sesión único sin tener que preguntar al usuario otra vez, hasta que caduque. Esta capacidad ofrece más flexibilidad al proveedor para realizar el inicio de sesión único y es obligatoria cuando tiene distintas entidades configuradas en las aplicaciones.
Además de la interfaz RememberMeIdentityStore definida en la especificación, también puede utilizar el token LTPA en la cookie LTPA que genera Liberty para lograr el SSO. Tenga en cuenta la siguiente información cuando utilice el cookie TPA en una aplicación JSR 375.
- Cuando se utiliza la especificación JSR 375, se añade información adicional a la señal en el cookie LTPA. Cuando esta señal LTPA se devuelve de nuevo o se dirige a otro servidor del mismo dominio de SSO, se valida. Si la validación es satisfactoria se invoca la implementación HttpAuthenticationMechanism, o un proveedor JASPIC si así está configurado, para completar la autenticación.
- Si el SSO se realiza únicamente entre aplicaciones JSR 375 habilitadas y solo se utilizan las implementaciones HttpAuthMechanism predeterminadas, la señal LTPA se valida. Si la validación resulta satisfactoria, no se vuelve a solicitar al usuario que inicie la sesión. La validación de la señal requiere que se intercambien las claves LTPA y que el registro de usuario sea el mismo, o que tenga configurados los mismos almacenes de identidades en todas las aplicaciones. Si la validación falla, se indica al usuario que inicie la sesión en base a la implementación HttpAuthMechanism configurada en la aplicación. Para obtener más información sobre SSO basado en señales LTPA que se basa en una señal, consulte Personalización de la configuración de SSO utilizando cookies LTPA en Liberty.
- Si se presenta un cookie LTPA desde una aplicación que no es JSR 375 a una aplicación habilitada para JSR 375, se invoca la implementación HttpAuthenticationMechanism aunque se valide la señal. Esta llamada se realiza siguiendo los requisitos de la especificación. Este requisito también se cumple cuando se configura un proveedor JASPIC. Entonces, la implementación HttpAuthMechanism vuelve a interpelar al usuario.
- Quizá no todos los usuarios deseen ser interpelados nuevo tal come se indica. Por ejemplo, podría utilizar la señal
LTPA validada para autenticar al usuario sin invocar la implementación HttpAuthenticationMechanism ni
un proveedor JASPIC. En esta situación, establezca la propiedad siguiente en el archivo server.xml:
<webAppSecurity useLtpaSSOForJaspic="true" /> - Cuando se establece esta propiedad y se presenta una señal LTPA válida, la señal se utiliza para autenticar al usuario sin invocar la implementación HttpAuthenticationMechanism ni el proveedor ASPIC. Establezca este distintivo en true solamente si el registro de usuarios es el mismo en todos los servidores que participan en el inicio de sesión único (SSO). Si hay algún almacén de identidades especificado en el código, no establezca el distintivo porque la implementación identitystores podría no ser la misma en todas las aplicaciones en todos los servidores. Un escenario común donde se establece este distintivo seria uno que solo especifica la anotación HttpAuthMechanism en el código, sin especificar ningún almacén de identidades. En este caso, se utiliza el registro de usuarios que está configurado en el archivo server.xml.
- Si desea especificar un cookie LTPA específico, puede establecer un nombre de cookie LTPA personalizado y específico para cada
servidor, estableciendo el siguiente atributo ssoCookieName. En este caso, el servidor solo genera y verifica el cookie
LTPA específico que está configurado. Cualquier otro cookie LTPA generado por
otros servidores no se utiliza.
<webAppSecurity useOnlyCustomCookieName="true", ssoCookieName="myServerXCookieName" /> ------> Change the cookieName and make it unique across all the servers - Si el cookie LTPA generado desde un servidor JSR 375 o un servidor JASPIC se presenta a un servidor que no es JSR 375 ni JASPIC, se valida y utiliza para el inicio de sesión único sin preguntar al usuario.