2011-05-31 12 views
14

La página "Http Authentication" de Oracle de la documentación de Java SE 6 dice que "si se está ejecutando en una máquina con Windows como usuario de dominio o se está ejecutando en una máquina Linux o Solaris que ya emitió el comando kinit y obtuvo la caché de credenciales "entonces la instancia pasó a Authenticator.setDefault()" será completamente ignorada ".¿Puede desactivarse el 'inicio de sesión único' de Java (usar las credenciales de 'Administrador de credenciales') en Windows?

Esto coincide con lo que observé: configurar una conexión HTTP o HTTPS en un sistema Windows al host X siempre pasa las credenciales para el host X desde 'Windows Credentials' de 'Windows Vault', como se ve en mi Windows 7 Página del Panel de control 'Credential Manager'.

Sin embargo,, en mi caso de uso, no quiero usar ninguna credencial que pueda ser almacenada por Windows, pero siempre quiero usar las credenciales que especifico explícitamente en el código.

¿Hay alguna manera de anular el comportamiento documentado, es decir, hay alguna manera de ignorar las credenciales almacenadas por Windows?

Actualización: Si no, ¿podría alguien indicarme un lugar en el código fuente de Java SE 6 donde pueda ver que las credenciales de Windows almacenadas no se pueden ignorar?

+0

Puede encontrar el código que valida si usa Credenciales de Windows en la clase 'sun.net.www.protocol.http.HttpURLConnection'. Eche un vistazo a la creación de instancias de 'NTLMAuthentication' y la bandera 'tryTransparentNTLMServer'.Estoy buscando hacer lo mismo que tú, pero tampoco estoy seguro de cómo hacer eso. – jmend

Respuesta

6

He buscado lo mismo que está preguntando. Hasta el momento, no he encontrado una manera en el JDK para hacer eso.

Hay una solicitud de mejora en la base de datos de errores de Java. Eche un vistazo al report para averiguar si Sun recibe una respuesta (vote el informe para que eso se resuelva pronto).

Lo que terminé haciendo, fue anular sun.net.www.protocol.http.NTLMAuthentication clase. Al observar sun.net.www.protocol.http.HttpURLAuthentication, descubrí que la única cosa que hay que modificar es el resultado de:

NTLMAuthentication.supportsTransparentAuth() 

Ese método tiene un valor de retorno codificada, true en plataformas Windows y false lo contrario. Este código se extrae de un JDK instalado en Windows 7:

static boolean supportsTransparentAuth() 
{ 
    return true; 
} 

Qué dice ese método es que si las credenciales de Windows debe ser utilizado por defecto. Si se establece en true, , su código personalizado de Autenticador no se llamará. Ver este fragmento de HttpURLConnection clase:

//Declared as a member variable of HttpURLConnection 
private boolean tryTransparentNTLMServer = NTLMAuthentication.supportsTransparentAuth(); 

//Inside of getServerAuthentication method. 
PasswordAuthentication a = null; 
if (!tryTransparentNTLMServer) { 
    //If set to false, this will call Authenticator.requestPasswordAuthentication(). 
    a = privilegedRequestPasswordAuthentication(url.getHost(), addr, port, url.getProtocol(), "", scheme, url, RequestorType.SERVER); 
} 

/* If we are not trying transparent authentication then 
* we need to have a PasswordAuthentication instance. For 
* transparent authentication (Windows only) the username 
* and password will be picked up from the current logged 
* on users credentials. 
*/ 
if (tryTransparentNTLMServer || (!tryTransparentNTLMServer && a != null)) { 
    //If set to true or if Authenticator did not return any credentials, use Windows credentials. 
    //NTLMAuthentication constructor, if receives a == null will fetch current looged user credentials. 
    ret = new NTLMAuthentication(false, url1, a); 
} 

Para obtener NTLMAuthentication código fuente, solía this Java decompiler. Abrió rt.jar ubicado en la carpeta de instalación de JDK y copió el código de clase deseado.

Entonces, simplemente cambié supportsTransparentAuth para devolver falso. Sin embargo, sería muy conveniente si este método verifica primero una propiedad del sistema y luego devuelve verdadero o falso en función de eso.

Para compilar, me acaba de colocar el archivo Java bajo http estructura de sol/net/www/protocolo/carpeta y ejecutar:

javac NTLMAuthentication.java 

A continuación, ejecute mi solicitud usando:

java -Xbootclasspath:"path/to/your/sun/net/www/protocol/http/classes;normal/JDK/boot/directories" 

Eso le indicará a la JVM que cargue nuestra implementación de NTLMAuthentication antes que la de rt.jar. Debe tener cuidado de no perder ninguna ruta de carga de clase predeterminada con -Xbootclasspath, o habrá ClassNotFound errores.

Después de eso, todo funcionó bien.

Este enfoque tiene importantes inconvenientes que debe tener en cuenta.

  • Existen riesgos de seguridad. Cualquiera puede colocar un archivo .class diferente en la carpeta de inicio y robar las credenciales del usuario u otra información importante.
  • El código de los paquetes de Sun puede cambiar sin previo aviso y, por lo tanto, será incompatible con sus cambios.
  • Si implementa este código, estará contraviniendo la licencia de Sun. Desde el documentation:

-Xbootclasspath: bootclasspath Especifica una lista separada por comas de los directorios, archivos JAR, y ZIP para buscar la clase de arranque archivos. Estos se utilizan en lugar de los archivos de clase de arranque incluidos en el SDK Java 2 . Nota: Las aplicaciones que usan esta opción para el propósito de anulando una clase en rt.jar no deberían implementarse porque al hacerlo, contravendría la licencia de código binario de Java 2 Runtime Environment.

Por lo tanto, esto definitivamente no es adecuado para entornos de producción.

Por último, esta es una excelente fuente sobre la opción de ruta de clases de arranque y cargadores de clases Java: PDF

Espero que esto ayude.

+0

Gracias. He aceptado esta respuesta, y esto concuerda con mi propio análisis anterior (también por descompilación del código de Sun JRE) de que no hay forma de evitar esto con el código estándar de Sun. Gracias por encontrar una manera de evitar este defecto de diseño (como yo lo veo), pero esto fue pensado para el uso de producción, y definitivamente no voy a (díganle a los colegas que) lo usen. Voy a votar por este Bug ID 7133281 en su lugar. –

+0

Sí, para el uso en producción esto debe evitarse definitivamente. Afortunadamente, solo lo necesitaba para una demostración, así que funcionó para mí. – jmend

+1

Si alguien llega a esto, hay un enfoque mucho más simple que consiste en usar [Apache HTTP Client 4] (http://hc.apache.org/httpcomponents-client-ga/) en lugar de Java subyacente [HTTP API] (http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html). En mi caso particular, terminé usando una combinación de [Apache HTTP Client] (http://hc.apache.org/httpcomponents-client-ga/) y [JCIFs NTLM] (http://jcifs.samba.org /src/docs/ntlmhttpauth.html) implementación para resolver todos los problemas relacionados con NTLM en Java. – jmend

6

Al menos en Java 7 hay una clase llamada sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback que parece ayudar con esta situación. El inicio de sesión único solo se invoca para las URL "confiables".

Aquí es la aplicación más sencilla para apagarlo (este initialiser han llamado antes de abrir la conexión HTTP):

static { 
    NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback() 
    { 
     @Override 
     public boolean isTrustedSite(URL url) 
     { 
      return false; 
     } 
    }); 
} 

supongo que la implementación por defecto es confiar en todo :(

+2

+1 para este hallazgo. Y sí, veo en [DefaultNTLMAuthenticationCallback] (http://www.docjar.com/docs/api/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback$DefaultNTLMAuthenticationCallback.html#isTrustedSite%28URL%29) que el la implementación predeterminada es intentar silenciosamente (lo que el JavaDoc llama 'transparente') autenticación. –

2

Parece . que la sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback clase se añadió a java 6,0 parche 24+ por lo que la solución sugerida puede trabajar en java 6.0, así Véase la referencia en el siguiente mensaje: http://www.mail-archive.com/[email protected]/msg22897.html

+0

+1 ¡Gracias! Tenga en cuenta que la publicación referida dice que el nombre del paquete en Java 6 es diferente, es decir. 'sun.net.www.protocol.http'. –

Cuestiones relacionadas