From 0ae598912163a9e267d151075801b12eb6dfd298 Mon Sep 17 00:00:00 2001 From: chegar Date: Wed, 21 Oct 2009 15:41:42 +0100 Subject: [PATCH] 6893238: Move NTLM and SPNEGO implementations into separate packages Reviewed-by: michaelm, alanb --- jdk/make/java/net/Makefile | 2 +- jdk/make/sun/net/FILES_java.gmk | 9 +- .../www/protocol/http/AuthenticationInfo.java | 36 +- .../protocol/http/BasicAuthentication.java | 23 +- .../protocol/http/DigestAuthentication.java | 23 +- .../www/protocol/http/HttpURLConnection.java | 13 +- .../http/NTLMAuthenticationProxy.java | 2 +- .../http/NegotiateAuthentication.java | 99 +--- .../sun/net/www/protocol/http/Negotiator.java | 82 ++++ .../NegotiateCallbackHandler.java | 4 +- .../http/{ => spnego}/NegotiatorImpl.java | 6 +- .../classes/sun/security/jgss/GSSUtil.java | 2 +- .../http/ntlm/NTLMAuthentication.java | 423 ++++++++++++++++++ .../http/{ => ntlm}/NTLMAuthSequence.java | 2 +- .../http/{ => ntlm}/NTLMAuthentication.java | 36 +- .../http/{ => ntlm}/NTLMAuthSequence.c | 6 +- 16 files changed, 605 insertions(+), 163 deletions(-) create mode 100644 jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java rename jdk/src/share/classes/sun/net/www/protocol/http/{ => spnego}/NegotiateCallbackHandler.java (97%) rename jdk/src/share/classes/sun/net/www/protocol/http/{ => spnego}/NegotiatorImpl.java (97%) create mode 100644 jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java rename jdk/src/windows/classes/sun/net/www/protocol/http/{ => ntlm}/NTLMAuthSequence.java (98%) rename jdk/src/windows/classes/sun/net/www/protocol/http/{ => ntlm}/NTLMAuthentication.java (89%) rename jdk/src/windows/native/sun/net/www/protocol/http/{ => ntlm}/NTLMAuthSequence.c (97%) diff --git a/jdk/make/java/net/Makefile b/jdk/make/java/net/Makefile index 203b059a38..3c0985bcf9 100644 --- a/jdk/make/java/net/Makefile +++ b/jdk/make/java/net/Makefile @@ -83,7 +83,7 @@ endif # # Find platform specific native code # -vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http $(PLATFORM_SRC)/native/sun/net/spi +vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi # # Include rules diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk index 19dd2d6d7f..a980f0b268 100644 --- a/jdk/make/sun/net/FILES_java.gmk +++ b/jdk/make/sun/net/FILES_java.gmk @@ -89,11 +89,12 @@ FILES_java = \ sun/net/www/protocol/http/AuthScheme.java \ sun/net/www/protocol/http/BasicAuthentication.java \ sun/net/www/protocol/http/DigestAuthentication.java \ - sun/net/www/protocol/http/NTLMAuthentication.java \ sun/net/www/protocol/http/NTLMAuthenticationProxy.java \ sun/net/www/protocol/http/NegotiateAuthentication.java \ - sun/net/www/protocol/http/NegotiatorImpl.java \ - sun/net/www/protocol/http/NegotiateCallbackHandler.java \ + sun/net/www/protocol/http/Negotiator.java \ + sun/net/www/protocol/http/ntlm/NTLMAuthentication.java \ + sun/net/www/protocol/http/spnego/NegotiatorImpl.java \ + sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java \ sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java \ sun/net/www/protocol/https/HttpsClient.java \ sun/net/www/protocol/https/DefaultHostnameVerifier.java \ @@ -128,7 +129,7 @@ FILES_java = \ sun/net/idn/StringPrep.java ifeq ($(PLATFORM), windows) - FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java + FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java endif ifeq ($(PLATFORM), solaris) diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java index cb3362efe8..1fbf5def0a 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java @@ -25,12 +25,10 @@ package sun.net.www.protocol.http; -import java.io.*; -import java.net.*; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.ListIterator; -import java.util.Enumeration; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.net.PasswordAuthentication; +import java.net.URL; import java.util.HashMap; import sun.net.www.HeaderParser; @@ -51,12 +49,12 @@ import sun.net.www.HeaderParser; // policy in HttpURLConnection. A failure on baz.foo.com shouldn't // uncache foo.com! -abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { +public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { // Constants saying what kind of authroization this is. This determines // the namespace in the hash table lookup. - static final char SERVER_AUTHENTICATION = 's'; - static final char PROXY_AUTHENTICATION = 'p'; + public static final char SERVER_AUTHENTICATION = 's'; + public static final char PROXY_AUTHENTICATION = 'p'; /** * If true, then simultaneous authentication requests to the same realm/proxy @@ -188,7 +186,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { String path; /** Use this constructor only for proxy entries */ - AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) { + public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) { this.type = type; this.authScheme = authScheme; this.protocol = ""; @@ -211,7 +209,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { * Constructor used to limit the authorization to the path within * the URL. Use this constructor for origin server entries. */ - AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) { + public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) { this.type = type; this.authScheme = authScheme; this.protocol = url.getProtocol().toLowerCase(); @@ -358,13 +356,19 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { /** * @return true if this authentication supports preemptive authorization */ - abstract boolean supportsPreemptiveAuthorization(); + public abstract boolean supportsPreemptiveAuthorization(); /** * @return the name of the HTTP header this authentication wants set. * This is used for preemptive authorization. */ - abstract String getHeaderName(); + public String getHeaderName() { + if (type == SERVER_AUTHENTICATION) { + return "Authorization"; + } else { + return "Proxy-authorization"; + } + } /** * Calculates and returns the authentication header value based @@ -375,7 +379,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { * @return the value of the HTTP header this authentication wants set. * Used for preemptive authorization. */ - abstract String getHeaderValue(URL url, String method); + public abstract String getHeaderValue(URL url, String method); /** * Set header(s) on the given connection. Subclasses must override @@ -386,7 +390,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { * @param raw The raw header field (if needed) * @return true if all goes well, false if no headers were set. */ - abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw); + public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw); /** * Check if the header indicates that the current auth. parameters are stale. @@ -396,7 +400,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable { * returning false means we have to go back to the user to ask for a new * username password. */ - abstract boolean isAuthorizationStale (String header); + public abstract boolean isAuthorizationStale (String header); /** * Give a key for hash table lookups. diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java index 7a92067f05..8e9c8a7281 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java @@ -131,21 +131,11 @@ class BasicAuthentication extends AuthenticationInfo { /** * @return true if this authentication supports preemptive authorization */ - boolean supportsPreemptiveAuthorization() { + @Override + public boolean supportsPreemptiveAuthorization() { return true; } - /** - * @return the name of the HTTP header this authentication wants set - */ - String getHeaderName() { - if (type == SERVER_AUTHENTICATION) { - return "Authorization"; - } else { - return "Proxy-authorization"; - } - } - /** * Set header(s) on the given connection. This will only be called for * definitive (i.e. non-preemptive) authorization. @@ -154,7 +144,8 @@ class BasicAuthentication extends AuthenticationInfo { * @param raw The raw header values for this connection, if needed. * @return true if all goes well, false if no headers were set. */ - boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + @Override + public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null)); return true; } @@ -162,7 +153,8 @@ class BasicAuthentication extends AuthenticationInfo { /** * @return the value of the HTTP header this authentication wants set */ - String getHeaderValue(URL url, String method) { + @Override + public String getHeaderValue(URL url, String method) { /* For Basic the authorization string does not depend on the request URL * or the request method */ @@ -174,7 +166,8 @@ class BasicAuthentication extends AuthenticationInfo { * In other words there is no possibility to reuse the credentials. * They are always either valid or invalid. */ - boolean isAuthorizationStale (String header) { + @Override + public boolean isAuthorizationStale (String header) { return false; } diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java index e62e3c2ecc..5ac4250587 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java @@ -200,21 +200,11 @@ class DigestAuthentication extends AuthenticationInfo { /** * @return true if this authentication supports preemptive authorization */ - boolean supportsPreemptiveAuthorization() { + @Override + public boolean supportsPreemptiveAuthorization() { return true; } - /** - * @return the name of the HTTP header this authentication wants set - */ - String getHeaderName() { - if (type == SERVER_AUTHENTICATION) { - return "Authorization"; - } else { - return "Proxy-Authorization"; - } - } - /** * Reclaculates the request-digest and returns it. * @@ -229,7 +219,8 @@ class DigestAuthentication extends AuthenticationInfo { * * @return the value of the HTTP header this authentication wants set */ - String getHeaderValue(URL url, String method) { + @Override + public String getHeaderValue(URL url, String method) { return getHeaderValueImpl(url.getFile(), method); } @@ -259,7 +250,8 @@ class DigestAuthentication extends AuthenticationInfo { * returning false means we have to go back to the user to ask for a new * username password. */ - boolean isAuthorizationStale (String header) { + @Override + public boolean isAuthorizationStale (String header) { HeaderParser p = new HeaderParser (header); String s = p.findValue ("stale"); if (s == null || !s.equals("true")) @@ -279,7 +271,8 @@ class DigestAuthentication extends AuthenticationInfo { * @param raw Raw header values for this connection, if needed. * @return true if all goes well, false if no headers were set. */ - boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + @Override + public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { params.setNonce (p.findValue("nonce")); params.setOpaque (p.findValue("opaque")); params.setQop (p.findValue("qop")); diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index c872526e59..bb37ff9d77 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -243,7 +243,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { private boolean tryTransparentNTLMProxy = true; /* Used by Windows specific code */ - Object authObj; + private Object authObj; /* Set if the user is manually setting the Authorization or Proxy-Authorization headers */ boolean isUserServerAuth; @@ -332,6 +332,15 @@ public class HttpURLConnection extends java.net.HttpURLConnection { return logger; } + /* Used for Windows NTLM implementation */ + public Object authObj() { + return authObj; + } + + public void authObj(Object authObj) { + this.authObj = authObj; + } + /* * checks the validity of http message header and throws * IllegalArgumentException if invalid. @@ -2529,7 +2538,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { // Set a property for authentication. This can safely disregard // the connected test. // - void setAuthenticationProperty(String key, String value) { + public void setAuthenticationProperty(String key, String value) { checkMessageHeader(key, value); requests.set(key, value); } diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java b/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java index 646728fb9e..945a18396c 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java @@ -36,7 +36,7 @@ import sun.util.logging.PlatformLogger; */ class NTLMAuthenticationProxy { private static Method supportsTA; - private static final String clazzStr = "sun.net.www.protocol.http.NTLMAuthentication"; + private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication"; private static final String supportsTAStr = "supportsTransparentAuth"; static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication(); diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java index 6d3931d095..67271f128e 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java @@ -25,17 +25,13 @@ package sun.net.www.protocol.http; +import java.net.URL; +import java.io.IOException; +import java.net.Authenticator.RequestorType; import java.util.HashMap; - import sun.net.www.HeaderParser; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; -import sun.util.logging.PlatformLogger; - -import java.net.URL; -import java.io.IOException; -import java.net.Authenticator.RequestorType; -import java.lang.reflect.Constructor; import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE; import static sun.net.www.protocol.http.AuthScheme.KERBEROS; @@ -78,7 +74,8 @@ class NegotiateAuthentication extends AuthenticationInfo { /** * @return true if this authentication supports preemptive authorization */ - boolean supportsPreemptiveAuthorization() { + @Override + public boolean supportsPreemptiveAuthorization() { return false; } @@ -104,34 +101,24 @@ class NegotiateAuthentication extends AuthenticationInfo { return supported.get(hostname); } - try { - Negotiator neg = Negotiator.getSupported(hci); + Negotiator neg = Negotiator.getNegotiator(hci); + if (neg != null) { supported.put(hostname, true); // the only place cache.put is called. here we can make sure // the object is valid and the oneToken inside is not null cache.put(hostname, neg); return true; - } catch(Exception e) { + } else { supported.put(hostname, false); return false; } } - /** - * @return the name of the HTTP header this authentication wants to set - */ - String getHeaderName() { - if (type == SERVER_AUTHENTICATION) { - return "Authorization"; - } else { - return "Proxy-Authorization"; - } - } - /** * Not supported. Must use the setHeaders() method */ - String getHeaderValue(URL url, String method) { + @Override + public String getHeaderValue(URL url, String method) { throw new RuntimeException ("getHeaderValue not supported"); } @@ -143,7 +130,8 @@ class NegotiateAuthentication extends AuthenticationInfo { * returning false means we have to go back to the user to ask for a new * username password. */ - boolean isAuthorizationStale (String header) { + @Override + public boolean isAuthorizationStale (String header) { return false; /* should not be called for Negotiate */ } @@ -155,7 +143,8 @@ class NegotiateAuthentication extends AuthenticationInfo { * @param raw The raw header field. * @return true if all goes well, false if no headers were set. */ - synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + @Override + public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { try { String response; @@ -177,7 +166,7 @@ class NegotiateAuthentication extends AuthenticationInfo { /** * return the first token. * @returns the token - * @throws IOException if Negotiator.getSupported() or + * @throws IOException if Negotiator.getNegotiator() or * Negotiator.firstToken() failed. */ private byte[] firstToken() throws IOException { @@ -191,11 +180,9 @@ class NegotiateAuthentication extends AuthenticationInfo { } } if (negotiator == null) { - try { - negotiator = Negotiator.getSupported(hci); - } catch(Exception e) { + negotiator = Negotiator.getNegotiator(hci); + if (negotiator == null) { IOException ioe = new IOException("Cannot initialize Negotiator"); - ioe.initCause(e); throw ioe; } } @@ -228,55 +215,3 @@ class NegotiateAuthentication extends AuthenticationInfo { // Currently we ignore this header. } - -/** - * This abstract class is a bridge to connect NegotiteAuthentication and - * NegotiatorImpl, so that JAAS and JGSS calls can be made - */ -abstract class Negotiator { - static Negotiator getSupported(HttpCallerInfo hci) - throws Exception { - - // These lines are equivalent to - // return new NegotiatorImpl(hci); - // The current implementation will make sure NegotiatorImpl is not - // directly referenced when compiling, thus smooth the way of building - // the J2SE platform where HttpURLConnection is a bootstrap class. - // - // Makes NegotiatorImpl, and the security classes it references, a - // runtime dependency rather than a static one. - - Class clazz; - Constructor c; - try { - clazz = Class.forName("sun.net.www.protocol.http.NegotiatorImpl", true, null); - c = clazz.getConstructor(HttpCallerInfo.class); - } catch (ClassNotFoundException cnfe) { - finest(cnfe); - throw cnfe; - } catch (ReflectiveOperationException roe) { - // if the class is there then something seriously wrong if - // the constructor is not. - throw new AssertionError(roe); - } - - try { - return (Negotiator) (c.newInstance(hci)); - } catch (ReflectiveOperationException roe) { - finest(roe); - Throwable t = roe.getCause(); - if (t != null && t instanceof Exception) - finest((Exception)t); - throw roe; - } - } - - abstract byte[] firstToken() throws IOException; - - abstract byte[] nextToken(byte[] in) throws IOException; - - static void finest(Exception e) { - PlatformLogger logger = HttpURLConnection.getHttpLogger(); - logger.finest("NegotiateAuthentication: " + e); - } -} diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java b/jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java new file mode 100644 index 0000000000..8cfc745cdb --- /dev/null +++ b/jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java @@ -0,0 +1,82 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.net.www.protocol.http; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import sun.util.logging.PlatformLogger; + +/** + * This abstract class is a bridge to connect NegotiteAuthentication and + * NegotiatorImpl, so that JAAS and JGSS calls can be made + */ +public abstract class Negotiator { + static Negotiator getNegotiator(HttpCallerInfo hci) { + + // These lines are equivalent to + // return new NegotiatorImpl(hci); + // The current implementation will make sure NegotiatorImpl is not + // directly referenced when compiling, thus smooth the way of building + // the J2SE platform where HttpURLConnection is a bootstrap class. + // + // Makes NegotiatorImpl, and the security classes it references, a + // runtime dependency rather than a static one. + + Class clazz; + Constructor c; + try { + clazz = Class.forName("sun.net.www.protocol.http.spnego.NegotiatorImpl", true, null); + c = clazz.getConstructor(HttpCallerInfo.class); + } catch (ClassNotFoundException cnfe) { + finest(cnfe); + return null; + } catch (ReflectiveOperationException roe) { + // if the class is there then something seriously wrong if + // the constructor is not. + throw new AssertionError(roe); + } + + try { + return (Negotiator) (c.newInstance(hci)); + } catch (ReflectiveOperationException roe) { + finest(roe); + Throwable t = roe.getCause(); + if (t != null && t instanceof Exception) + finest((Exception)t); + return null; + } + } + + public abstract byte[] firstToken() throws IOException; + + public abstract byte[] nextToken(byte[] in) throws IOException; + + private static void finest(Exception e) { + PlatformLogger logger = HttpURLConnection.getHttpLogger(); + logger.finest("NegotiateAuthentication: " + e); + } +} + diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateCallbackHandler.java b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java similarity index 97% rename from jdk/src/share/classes/sun/net/www/protocol/http/NegotiateCallbackHandler.java rename to jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java index 7ac25933ce..f2c0f6cc25 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateCallbackHandler.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java @@ -23,7 +23,8 @@ * have any questions. */ -package sun.net.www.protocol.http; +package sun.net.www.protocol.http.spnego; + import java.io.IOException; import java.net.Authenticator; import java.net.PasswordAuthentication; @@ -33,6 +34,7 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; +import sun.net.www.protocol.http.HttpCallerInfo; /** * @since 1.6 diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java similarity index 97% rename from jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java rename to jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java index 2c195e4022..dd4a39bd87 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java @@ -23,7 +23,7 @@ * have any questions. */ -package sun.net.www.protocol.http; +package sun.net.www.protocol.http.spnego; import java.io.IOException; @@ -32,6 +32,8 @@ import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSName; import org.ietf.jgss.Oid; +import sun.net.www.protocol.http.HttpCallerInfo; +import sun.net.www.protocol.http.Negotiator; import sun.security.jgss.GSSManagerImpl; import sun.security.jgss.GSSUtil; import sun.security.jgss.HttpCaller; @@ -133,6 +135,7 @@ public class NegotiatorImpl extends Negotiator { * Return the first token of GSS, in SPNEGO, it's called NegTokenInit * @return the first token */ + @Override public byte[] firstToken() { return oneToken; } @@ -143,6 +146,7 @@ public class NegotiatorImpl extends Negotiator { * @return the next token * @throws java.io.IOException if the token cannot be created successfully */ + @Override public byte[] nextToken(byte[] token) throws IOException { try { return context.initSecContext(token, 0, token.length); diff --git a/jdk/src/share/classes/sun/security/jgss/GSSUtil.java b/jdk/src/share/classes/sun/security/jgss/GSSUtil.java index 12a791dc4a..a59bf5dfab 100644 --- a/jdk/src/share/classes/sun/security/jgss/GSSUtil.java +++ b/jdk/src/share/classes/sun/security/jgss/GSSUtil.java @@ -237,7 +237,7 @@ public class GSSUtil { CallbackHandler cb = null; if (caller instanceof HttpCaller) { - cb = new sun.net.www.protocol.http.NegotiateCallbackHandler( + cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler( ((HttpCaller)caller).info()); } else { String defaultHandler = diff --git a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java new file mode 100644 index 0000000000..ef72df14fa --- /dev/null +++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -0,0 +1,423 @@ +/* + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.net.www.protocol.http.ntlm; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.PasswordAuthentication; +import java.net.UnknownHostException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; + +import sun.net.www.HeaderParser; +import sun.net.www.protocol.http.AuthenticationInfo; +import sun.net.www.protocol.http.AuthScheme; +import sun.net.www.protocol.http.HttpURLConnection; + +/** + * NTLMAuthentication: + * + * @author Michael McMahon + */ + +/* + * NTLM authentication is nominally based on the framework defined in RFC2617, + * but differs from the standard (Basic & Digest) schemes as follows: + * + * 1. A complete authentication requires three request/response transactions + * as shown below: + * REQ -------------------------------> + * <---- 401 (signalling NTLM) -------- + * + * REQ (with type1 NTLM msg) ---------> + * <---- 401 (with type 2 NTLM msg) --- + * + * REQ (with type3 NTLM msg) ---------> + * <---- OK --------------------------- + * + * 2. The scope of the authentication is the TCP connection (which must be kept-alive) + * after the type2 response is received. This means that NTLM does not work end-to-end + * through a proxy, rather between client and proxy, or between client and server (with no proxy) + */ + +public class NTLMAuthentication extends AuthenticationInfo { + private static final long serialVersionUID = -2403849171106437142L; + + private byte[] type1; + private byte[] type3; + + private SecretKeyFactory fac; + private Cipher cipher; + private MessageDigest md4; + private String hostname; + private static String defaultDomain; /* Domain to use if not specified by user */ + + static { + defaultDomain = java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("http.auth.ntlm.domain", + "domain")); + }; + + public static boolean supportsTransparentAuth () { + return false; + } + + private void init0() { + type1 = new byte[256]; + type3 = new byte[256]; + System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9); + type1[12] = (byte) 3; + type1[13] = (byte) 0xb2; + type1[28] = (byte) 0x20; + System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,3}, 0, type3, 0, 9); + type3[12] = (byte) 0x18; + type3[14] = (byte) 0x18; + type3[20] = (byte) 0x18; + type3[22] = (byte) 0x18; + type3[32] = (byte) 0x40; + type3[60] = (byte) 1; + type3[61] = (byte) 0x82; + + try { + hostname = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public String run() { + String localhost; + try { + localhost = InetAddress.getLocalHost().getHostName().toUpperCase(); + } catch (UnknownHostException e) { + localhost = "localhost"; + } + return localhost; + } + }); + int x = hostname.indexOf ('.'); + if (x != -1) { + hostname = hostname.substring (0, x); + } + fac = SecretKeyFactory.getInstance ("DES"); + cipher = Cipher.getInstance ("DES/ECB/NoPadding"); + md4 = sun.security.provider.MD4.getInstance(); + } catch (NoSuchPaddingException e) { + assert false; + } catch (NoSuchAlgorithmException e) { + assert false; + } + }; + + PasswordAuthentication pw; + String username; + String ntdomain; + String password; + + /** + * Create a NTLMAuthentication: + * Username may be specified as domainusername in the application Authenticator. + * If this notation is not used, then the domain will be taken + * from a system property: "http.auth.ntlm.domain". + */ + public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) { + super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, + AuthScheme.NTLM, + url, + ""); + init (pw); + } + + private void init (PasswordAuthentication pw) { + this.pw = pw; + String s = pw.getUserName(); + int i = s.indexOf ('\\'); + if (i == -1) { + username = s; + ntdomain = defaultDomain; + } else { + ntdomain = s.substring (0, i).toUpperCase(); + username = s.substring (i+1); + } + password = new String (pw.getPassword()); + init0(); + } + + /** + * Constructor used for proxy entries + */ + public NTLMAuthentication(boolean isProxy, String host, int port, + PasswordAuthentication pw) { + super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION, + AuthScheme.NTLM, + host, + port, + ""); + init (pw); + } + + /** + * @return true if this authentication supports preemptive authorization + */ + @Override + public boolean supportsPreemptiveAuthorization() { + return false; + } + + /** + * Not supported. Must use the setHeaders() method + */ + @Override + public String getHeaderValue(URL url, String method) { + throw new RuntimeException ("getHeaderValue not supported"); + } + + /** + * Check if the header indicates that the current auth. parameters are stale. + * If so, then replace the relevant field with the new value + * and return true. Otherwise return false. + * returning true means the request can be retried with the same userid/password + * returning false means we have to go back to the user to ask for a new + * username password. + */ + @Override + public boolean isAuthorizationStale (String header) { + return false; /* should not be called for ntlm */ + } + + /** + * Set header(s) on the given connection. + * @param conn The connection to apply the header(s) to + * @param p A source of header values for this connection, not used because + * HeaderParser converts the fields to lower case, use raw instead + * @param raw The raw header field. + * @return true if all goes well, false if no headers were set. + */ + @Override + public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + + try { + String response; + if (raw.length() < 6) { /* NTLM */ + response = buildType1Msg (); + } else { + String msg = raw.substring (5); /* skip NTLM */ + response = buildType3Msg (msg); + } + conn.setAuthenticationProperty(getHeaderName(), response); + return true; + } catch (IOException e) { + return false; + } catch (GeneralSecurityException e) { + return false; + } + } + + private void copybytes (byte[] dest, int destpos, String src, String enc) { + try { + byte[] x = src.getBytes(enc); + System.arraycopy (x, 0, dest, destpos, x.length); + } catch (UnsupportedEncodingException e) { + assert false; + } + } + + private String buildType1Msg () { + int dlen = ntdomain.length(); + type1[16]= (byte) (dlen % 256); + type1[17]= (byte) (dlen / 256); + type1[18] = type1[16]; + type1[19] = type1[17]; + + int hlen = hostname.length(); + type1[24]= (byte) (hlen % 256); + type1[25]= (byte) (hlen / 256); + type1[26] = type1[24]; + type1[27] = type1[25]; + + copybytes (type1, 32, hostname, "ISO8859_1"); + copybytes (type1, hlen+32, ntdomain, "ISO8859_1"); + type1[20] = (byte) ((hlen+32) % 256); + type1[21] = (byte) ((hlen+32) / 256); + + byte[] msg = new byte [32 + hlen + dlen]; + System.arraycopy (type1, 0, msg, 0, 32 + hlen + dlen); + String result = "NTLM " + (new B64Encoder()).encode (msg); + return result; + } + + + /* Convert a 7 byte array to an 8 byte array (for a des key with parity) + * input starts at offset off + */ + private byte[] makeDesKey (byte[] input, int off) { + int[] in = new int [input.length]; + for (int i=0; i> 1)); + out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2)); + out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3)); + out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4)); + out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5)); + out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6)); + out[7] = (byte)((in[off+6] << 1) & 0xFF); + return out; + } + + private byte[] calcLMHash () throws GeneralSecurityException { + byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + byte[] pwb = password.toUpperCase ().getBytes(); + byte[] pwb1 = new byte [14]; + int len = password.length(); + if (len > 14) + len = 14; + System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */ + + DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0)); + DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7)); + + SecretKey key1 = fac.generateSecret (dks1); + SecretKey key2 = fac.generateSecret (dks2); + cipher.init (Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal (magic, 0, 8); + cipher.init (Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal (magic, 0, 8); + + byte[] result = new byte [21]; + System.arraycopy (out1, 0, result, 0, 8); + System.arraycopy (out2, 0, result, 8, 8); + return result; + } + + private byte[] calcNTHash () throws GeneralSecurityException { + byte[] pw = null; + try { + pw = password.getBytes ("UnicodeLittleUnmarked"); + } catch (UnsupportedEncodingException e) { + assert false; + } + byte[] out = md4.digest (pw); + byte[] result = new byte [21]; + System.arraycopy (out, 0, result, 0, 16); + return result; + } + + /* key is a 21 byte array. Split it into 3 7 byte chunks, + * Convert each to 8 byte DES keys, encrypt the text arg with + * each key and return the three results in a sequential [] + */ + private byte[] calcResponse (byte[] key, byte[] text) + throws GeneralSecurityException { + assert key.length == 21; + DESKeySpec dks1 = new DESKeySpec (makeDesKey (key, 0)); + DESKeySpec dks2 = new DESKeySpec (makeDesKey (key, 7)); + DESKeySpec dks3 = new DESKeySpec (makeDesKey (key, 14)); + SecretKey key1 = fac.generateSecret (dks1); + SecretKey key2 = fac.generateSecret (dks2); + SecretKey key3 = fac.generateSecret (dks3); + cipher.init (Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal (text, 0, 8); + cipher.init (Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal (text, 0, 8); + cipher.init (Cipher.ENCRYPT_MODE, key3); + byte[] out3 = cipher.doFinal (text, 0, 8); + byte[] result = new byte [24]; + System.arraycopy (out1, 0, result, 0, 8); + System.arraycopy (out2, 0, result, 8, 8); + System.arraycopy (out3, 0, result, 16, 8); + return result; + } + + private String buildType3Msg (String challenge) throws GeneralSecurityException, + IOException { + /* First decode the type2 message to get the server nonce */ + /* nonce is located at type2[24] for 8 bytes */ + + byte[] type2 = (new sun.misc.BASE64Decoder()).decodeBuffer (challenge); + byte[] nonce = new byte [8]; + System.arraycopy (type2, 24, nonce, 0, 8); + + int ulen = username.length()*2; + type3[36] = type3[38] = (byte) (ulen % 256); + type3[37] = type3[39] = (byte) (ulen / 256); + int dlen = ntdomain.length()*2; + type3[28] = type3[30] = (byte) (dlen % 256); + type3[29] = type3[31] = (byte) (dlen / 256); + int hlen = hostname.length()*2; + type3[44] = type3[46] = (byte) (hlen % 256); + type3[45] = type3[47] = (byte) (hlen / 256); + + int l = 64; + copybytes (type3, l, ntdomain, "UnicodeLittleUnmarked"); + type3[32] = (byte) (l % 256); + type3[33] = (byte) (l / 256); + l += dlen; + copybytes (type3, l, username, "UnicodeLittleUnmarked"); + type3[40] = (byte) (l % 256); + type3[41] = (byte) (l / 256); + l += ulen; + copybytes (type3, l, hostname, "UnicodeLittleUnmarked"); + type3[48] = (byte) (l % 256); + type3[49] = (byte) (l / 256); + l += hlen; + + byte[] lmhash = calcLMHash(); + byte[] lmresponse = calcResponse (lmhash, nonce); + byte[] nthash = calcNTHash(); + byte[] ntresponse = calcResponse (nthash, nonce); + System.arraycopy (lmresponse, 0, type3, l, 24); + type3[16] = (byte) (l % 256); + type3[17] = (byte) (l / 256); + l += 24; + System.arraycopy (ntresponse, 0, type3, l, 24); + type3[24] = (byte) (l % 256); + type3[25] = (byte) (l / 256); + l += 24; + type3[56] = (byte) (l % 256); + type3[57] = (byte) (l / 256); + + byte[] msg = new byte [l]; + System.arraycopy (type3, 0, msg, 0, l); + String result = "NTLM " + (new B64Encoder()).encode (msg); + return result; + } + +} + + +class B64Encoder extends sun.misc.BASE64Encoder { + /* to force it to to the entire encoding in one line */ + protected int bytesPerLine () { + return 1024; + } +} diff --git a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthSequence.java b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java similarity index 98% rename from jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthSequence.java rename to jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java index fff4afe902..9837ff69ad 100644 --- a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthSequence.java +++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java @@ -23,7 +23,7 @@ * have any questions. */ -package sun.net.www.protocol.http; +package sun.net.www.protocol.http.ntlm; import java.io.IOException; import sun.misc.BASE64Encoder; diff --git a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java similarity index 89% rename from jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java rename to jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index d3be682016..90f94b2317 100644 --- a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java +++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -23,7 +23,7 @@ * have any questions. */ -package sun.net.www.protocol.http; +package sun.net.www.protocol.http.ntlm; import java.io.IOException; import java.net.InetAddress; @@ -31,6 +31,9 @@ import java.net.PasswordAuthentication; import java.net.UnknownHostException; import java.net.URL; import sun.net.www.HeaderParser; +import sun.net.www.protocol.http.AuthenticationInfo; +import sun.net.www.protocol.http.AuthScheme; +import sun.net.www.protocol.http.HttpURLConnection; /** * NTLMAuthentication: @@ -38,7 +41,7 @@ import sun.net.www.HeaderParser; * @author Michael McMahon */ -class NTLMAuthentication extends AuthenticationInfo { +public class NTLMAuthentication extends AuthenticationInfo { private static final long serialVersionUID = 100L; @@ -127,32 +130,23 @@ class NTLMAuthentication extends AuthenticationInfo { /** * @return true if this authentication supports preemptive authorization */ - boolean supportsPreemptiveAuthorization() { + @Override + public boolean supportsPreemptiveAuthorization() { return false; } /** * @return true if NTLM supported transparently (no password needed, SSO) */ - static boolean supportsTransparentAuth() { + public static boolean supportsTransparentAuth() { return true; } - /** - * @return the name of the HTTP header this authentication wants set - */ - String getHeaderName() { - if (type == SERVER_AUTHENTICATION) { - return "Authorization"; - } else { - return "Proxy-authorization"; - } - } - /** * Not supported. Must use the setHeaders() method */ - String getHeaderValue(URL url, String method) { + @Override + public String getHeaderValue(URL url, String method) { throw new RuntimeException ("getHeaderValue not supported"); } @@ -164,7 +158,8 @@ class NTLMAuthentication extends AuthenticationInfo { * returning false means we have to go back to the user to ask for a new * username password. */ - boolean isAuthorizationStale (String header) { + @Override + public boolean isAuthorizationStale (String header) { return false; /* should not be called for ntlm */ } @@ -176,13 +171,14 @@ class NTLMAuthentication extends AuthenticationInfo { * @param raw The raw header field. * @return true if all goes well, false if no headers were set. */ - synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { + @Override + public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) { try { - NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj; + NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj(); if (seq == null) { seq = new NTLMAuthSequence (username, password, ntdomain); - conn.authObj = seq; + conn.authObj(seq); } String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null); conn.setAuthenticationProperty(getHeaderName(), response); diff --git a/jdk/src/windows/native/sun/net/www/protocol/http/NTLMAuthSequence.c b/jdk/src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c similarity index 97% rename from jdk/src/windows/native/sun/net/www/protocol/http/NTLMAuthSequence.c rename to jdk/src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c index 2ed53e0506..2812b46409 100644 --- a/jdk/src/windows/native/sun/net/www/protocol/http/NTLMAuthSequence.c +++ b/jdk/src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c @@ -60,7 +60,7 @@ static jfieldID ntlm_crdHandleID; static HINSTANCE lib = NULL; -JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_initFirst +JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_initFirst (JNIEnv *env, jclass clazz) { OSVERSIONINFO version; @@ -113,7 +113,7 @@ JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_initFirst * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J */ -JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_getCredentialsHandle +JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_getCredentialsHandle (JNIEnv *env, jobject this, jstring user, jstring domain, jstring password) { SEC_WINNT_AUTH_IDENTITY AuthId; @@ -197,7 +197,7 @@ JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_getCrede } } -JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_getNextToken +JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_getNextToken (JNIEnv *env, jobject this, jlong crdHandle, jbyteArray lastToken) { -- GitLab