ejemplo - active directory authentication java
Autenticación contra Active Directory con Java en Linux (9)
Tengo una tarea simple de autenticar contra Active Directory usando Java. Solo verificando credenciales y nada más. Digamos que mi dominio es "fun.xyz.tld", la ruta OU es desconocida y el nombre de usuario / contraseña es testu / testp.
Sé que hay algunas bibliotecas de Java que simplifican esta tarea, pero no tuve éxito en su implementación. La mayoría de los ejemplos que he encontrado abordan LDAP en general, no específicamente Active Directory. Emitir solicitud de LDAP significa enviar una ruta de acceso de unidad organizativa, que yo no tengo. Además, la aplicación que emite la solicitud LDAP ya debe estar vinculada a Active Directory para poder acceder a ella ... Inseguro, ya que las credenciales tendrían que almacenarse en algún lugar detectable. Me gustaría un enlace de prueba con credenciales de prueba, si es posible, esto significaría que la cuenta es válida.
Por último, si es posible, ¿hay alguna manera de cifrar ese mecanismo de autenticación? Sé que AD usa Kerberos, pero no estoy seguro de si los métodos LDAP de Java sí lo hacen.
¿Alguien tiene un ejemplo de código de trabajo? Gracias.
¿Estás solo verificando credenciales? En ese caso, podría hacer kerberos
simples y no molestarse con LDAP
.
Acabo de terminar un proyecto que usa AD y Java. Usamos Spring ldapTemplate.
AD cumple con LDAP (casi), no creo que tenga ningún problema con la tarea que tiene. Me refiero al hecho de que es AD o cualquier otro servidor LDAP, no importa si solo quieres conectarte.
Me gustaría echar un vistazo a: Primavera LDAP
Ellos tienen ejemplos también.
En cuanto al cifrado, utilizamos la conexión SSL (por lo que era LDAPS). AD tuvo que configurarse en un puerto / protocolo SSL.
Pero antes que nada, asegúrate de que puedes conectarte correctamente a tu AD a través de un IDE de LDAP. Uso Apache Directory Studio , es genial y está escrito en Java. Eso es todo lo que necesitaba. Para fines de prueba también puede instalar Apache Directory Server
Aquí está el código que armé basado en el ejemplo de este blog: LINK y esta fuente: LINK .
import com.sun.jndi.ldap.LdapCtxFactory;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Iterator;
import javax.naming.Context;
import javax.naming.AuthenticationException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import static javax.naming.directory.SearchControls.SUBTREE_SCOPE;
class App2 {
public static void main(String[] args) {
if (args.length != 4 && args.length != 2) {
System.out.println("Purpose: authenticate user against Active Directory and list group membership.");
System.out.println("Usage: App2 <username> <password> <domain> <server>");
System.out.println("Short usage: App2 <username> <password>");
System.out.println("(short usage assumes ''xyz.tld'' as domain and ''abc'' as server)");
System.exit(1);
}
String domainName;
String serverName;
if (args.length == 4) {
domainName = args[2];
serverName = args[3];
} else {
domainName = "xyz.tld";
serverName = "abc";
}
String username = args[0];
String password = args[1];
System.out
.println("Authenticating " + username + "@" + domainName + " through " + serverName + "." + domainName);
// bind by using the specified username/password
Hashtable props = new Hashtable();
String principalName = username + "@" + domainName;
props.put(Context.SECURITY_PRINCIPAL, principalName);
props.put(Context.SECURITY_CREDENTIALS, password);
DirContext context;
try {
context = LdapCtxFactory.getLdapCtxInstance("ldap://" + serverName + "." + domainName + ''/'', props);
System.out.println("Authentication succeeded!");
// locate this user''s record
SearchControls controls = new SearchControls();
controls.setSearchScope(SUBTREE_SCOPE);
NamingEnumeration<SearchResult> renum = context.search(toDC(domainName),
"(& (userPrincipalName=" + principalName + ")(objectClass=user))", controls);
if (!renum.hasMore()) {
System.out.println("Cannot locate user information for " + username);
System.exit(1);
}
SearchResult result = renum.next();
List<String> groups = new ArrayList<String>();
Attribute memberOf = result.getAttributes().get("memberOf");
if (memberOf != null) {// null if this user belongs to no group at all
for (int i = 0; i < memberOf.size(); i++) {
Attributes atts = context.getAttributes(memberOf.get(i).toString(), new String[] { "CN" });
Attribute att = atts.get("CN");
groups.add(att.get().toString());
}
}
context.close();
System.out.println();
System.out.println("User belongs to: ");
Iterator ig = groups.iterator();
while (ig.hasNext()) {
System.out.println(" " + ig.next());
}
} catch (AuthenticationException a) {
System.out.println("Authentication failed: " + a);
System.exit(1);
} catch (NamingException e) {
System.out.println("Failed to bind to LDAP / get account information: " + e);
System.exit(1);
}
}
private static String toDC(String domainName) {
StringBuilder buf = new StringBuilder();
for (String token : domainName.split("//.")) {
if (token.length() == 0)
continue; // defensive check
if (buf.length() > 0)
buf.append(",");
buf.append("DC=").append(token);
}
return buf.toString();
}
}
Como ioplex y otros han dicho, hay muchas opciones. Para autenticar usando LDAP (y la API de LDAP de Novell), he usado algo como:
LDAPConnection connection = new LDAPConnection( new LDAPJSSEStartTLSFactory() );
connection.connect(hostname, port);
connection.startTLS();
connection.bind(LDAPConnection.LDAP_V3, username+"@"+domain, password.getBytes());
Como una "característica especial", Active Directory permite que LDAP se vincule con "usuario @ dominio" sin usar el nombre completo de la cuenta. Este código usa StartTLS para habilitar el cifrado TLS en la conexión; la otra alternativa es LDAP sobre SSL, que no es compatible con mis servidores AD.
El verdadero truco está en ubicar el servidor y el host; la forma oficial es utilizar una búsqueda de registros DNS SRV (servicio) para localizar un paquete de hosts candidatos, luego hacer un "ping" de LDAP basado en UDP (en un formato particular de Microsoft) para ubicar el servidor correcto. Si está interesado, he publicado algunos artículos de blog sobre mi viaje de aventura y descubrimiento en esa área.
Si quiere hacer una autenticación de nombre de usuario / contraseña basada en Kerberos, está mirando otra olla de pescado; es factible con el código Java GSS-API, aunque no estoy seguro de que realice el último paso para validar la autenticación. (El código que realiza la validación puede comunicarse con el servidor de AD para verificar el nombre de usuario y la contraseña, lo que da como resultado un ticket de otorgamiento de ticket para el usuario, pero para asegurarse de que el servidor AD no sea suplantado, también debe intentar obtener un ticket para el usuario a sí mismo, que es algo más complicado).
Si desea realizar el inicio de sesión único basado en Kerberos, suponiendo que sus usuarios estén autenticados en el dominio, puede hacerlo también con el código GSS-API de Java. Publicaba una muestra de código, pero aún necesito convertir mi horrible prototipo en algo apto para ojos humanos. Eche un vistazo al código de SpringSource para obtener inspiración.
Si está buscando NTLM (que se me dio a entender que es menos seguro) o algo más, bueno, buena suerte.
Hay 3 protocolos de autenticación que se pueden usar para realizar la autenticación entre Java y Active Directory en Linux o en cualquier otra plataforma (y estos no son solo específicos de los servicios HTTP):
Kerberos: Kerberos proporciona inicio de sesión único (SSO) y delegación, pero los servidores web también necesitan el soporte de SPNEGO para aceptar SSO a través de IE.
NTLM: NTLM admite SSO a través de IE (y otros navegadores si están configurados correctamente).
LDAP: un enlace LDAP se puede usar para validar simplemente un nombre de cuenta y contraseña.
También hay algo llamado "ADFS" que proporciona SSO para sitios web que usan SAML que llama al SSP de Windows, por lo que en la práctica es básicamente una forma indirecta de utilizar uno de los otros protocolos anteriores.
Cada protocolo tiene sus ventajas, pero como regla general, para obtener la máxima compatibilidad, generalmente debe intentar "hacer lo mismo que Windows". Entonces, ¿qué hace Windows?
En primer lugar, la autenticación entre dos máquinas Windows favorece a Kerberos porque los servidores no necesitan comunicarse con el DC y los clientes pueden almacenar en caché los tickets Kerberos, lo que reduce la carga en los DC (y porque Kerberos admite la delegación).
Pero si las partes que autentican no tienen cuentas de dominio o si el cliente no puede comunicarse con el DC, se requiere NTLM. Así que Kerberos y NTLM no son mutuamente excluyentes y NTLM no está obsoleto por Kerberos. De hecho, en cierto modo, NTLM es mejor que Kerberos. Tenga en cuenta que al mencionar Kerberos y NTLM al mismo tiempo, también debo mencionar SPENGO y la Autenticación Integrada de Windows (IWA). IWA es un término simple que básicamente significa Kerberos, NTLM o SPNEGO para negociar Kerberos o NTLM.
El uso de un enlace LDAP como una forma de validar las credenciales no es eficiente y requiere SSL. Pero hasta hace poco la implementación de Kerberos y NTLM ha sido difícil, por lo que el uso de LDAP como un servicio de autenticación make-shift ha persistido. Pero en este punto, generalmente se debe evitar. LDAP es un directorio de información y no un servicio de autenticación. Úselo para su propósito previsto.
Entonces, ¿cómo implementar Kerberos o NTLM en Java y en el contexto de las aplicaciones web en particular?
Hay una serie de grandes empresas como Quest Software y Centrify que tienen soluciones que mencionan específicamente Java. Realmente no puedo comentar sobre estos ya que son "soluciones de gestión de identidad" para toda la compañía, por lo que, al mirar el giro de marketing en su sitio web, es difícil decir exactamente qué protocolos se usan y cómo. Debería ponerse en contacto con ellos para obtener más detalles.
La implementación de Kerberos en Java no es muy difícil ya que las bibliotecas estándar de Java son compatibles con Kerberos a través de las clases org.ietf.gssapi. Sin embargo, hasta hace poco ha habido un obstáculo importante: IE no envía tokens Kerberos brutos, sino que envía tokens SPNEGO. Pero con Java 6, se ha implementado SPNEGO. En teoría, debería poder escribir algún código GSSAPI que pueda autenticar a los clientes de IE. Pero no lo he intentado. La implementación de Sun de Kerberos ha sido una comedia de errores a lo largo de los años, por lo que, basado en el historial de Sun en esta área, no haría ninguna promesa sobre su implementación de SPENGO hasta que tenga ese ave en la mano.
Para NTLM, hay un proyecto de OSS gratuito llamado JCIFS que tiene un filtro de servlet de autenticación HTTP NTLM. Sin embargo, utiliza un método man-in-the-middle para validar las credenciales con un servidor SMB que no funciona con NTLMv2 (que lentamente se está convirtiendo en una política de seguridad de dominio requerida). Por ese motivo y otros, la parte del Filtro HTTP de JCIFS está programada para ser eliminada. Tenga en cuenta que hay un número de spin-offs que usan JCIFS para implementar la misma técnica. Por lo tanto, si ve otros proyectos que afirman ser compatibles con NTOS de NTLM, consulte la letra pequeña.
La única forma correcta de validar las credenciales NTLM con Active Directory es usar la llamada NetrLogonSamLogon DCERPC sobre NETLOGON con Secure Channel. ¿Existe tal cosa en Java? Sí. Aquí está:
http://www.ioplex.com/jespa.html
Jespa es una implementación 100% Java NTLM que admite NTLMv2, NTLMv1, integridad completa y opciones de confidencialidad y la validación de credenciales NETLOGON antes mencionada. E incluye un filtro HTTP SSO, un JAAS LoginModule, cliente HTTP, cliente y servidor SASL (con enlace JNDI), "proveedor de seguridad" genérico para crear servicios personalizados NTLM y más.
Micro
La autenticación ldap sin SSL no es segura y cualquiera puede ver las credenciales del usuario porque el usuario de transferencia ldap usernamae y la contraseña durante la operación de ldap bind. Así que siempre use el protocolo ldaps. fuente: autenticación Ldap Directorio activo en Java Spring Security con Ejemplo
Si todo lo que quiere hacer es autenticarse contra AD usando Kerberos, entonces un simple http://spnego.sourceforge.net/HelloKDC.java programa debería hacerlo.
Eche un vistazo a la documentación "previa al vuelo" del proyecto que habla sobre el programa HelloKDC.java.
Te recomiendo que veas el paquete adbroker del proyecto oVirt . Utiliza Spring-Ldap y el módulo de inicio de sesión de Krb5 JAAS (con GSSAPI) para autenticarse utilizando Kerberos contra servidores Ldap (Active-Directory, ipa, rhds, Tivoli-DS). Busque el código en el motor / backend / manager / modules / bll / src / main / java / org / ovirt / engine / core / bll / adbroker
Puedes usar git para clonar el repositorio o navegar usando el enlace gerrit
http://java.sun.com/docs/books/tutorial/jndi/ldap/auth_mechs.html
El mecanismo SASL es compatible con Kerberos v4 y v5. http://java.sun.com/docs/books/tutorial/jndi/ldap/sasl.html