feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
71
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCache.java
Normal file
71
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCache.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
/**
|
||||
* @author Michael McMahon
|
||||
*
|
||||
* Interface provided by internal http authentication cache.
|
||||
* NB. This API will be replaced in a future release, and should
|
||||
* not be made public.
|
||||
*/
|
||||
|
||||
public interface AuthCache {
|
||||
|
||||
/**
|
||||
* Put an entry in the cache. pkey is a string specified as follows:
|
||||
*
|
||||
* A:[B:]C:D:E[:F] Between 4 and 6 fields separated by ":"
|
||||
* where the fields have the following meaning:
|
||||
* A is "s" or "p" for server or proxy authentication respectively
|
||||
* B is optional and is the {@link AuthScheme}, e.g. BASIC, DIGEST, NTLM, etc
|
||||
* C is either "http" or "https"
|
||||
* D is the hostname
|
||||
* E is the port number
|
||||
* F is optional and if present is the realm
|
||||
*
|
||||
* Generally, two entries are created for each AuthCacheValue,
|
||||
* one including the realm and one without the realm.
|
||||
* Also, for some schemes (digest) multiple entries may be created
|
||||
* with the same pkey, but with a different path value in
|
||||
* the AuthCacheValue.
|
||||
*/
|
||||
public void put (String pkey, AuthCacheValue value);
|
||||
|
||||
/**
|
||||
* Get an entry from the cache based on pkey as described above, but also
|
||||
* using a pathname (skey) and the cache must return an entry
|
||||
* if skey is a sub-path of the AuthCacheValue.path field.
|
||||
*/
|
||||
public AuthCacheValue get (String pkey, String skey);
|
||||
|
||||
/**
|
||||
* remove the entry from the cache whose pkey is specified and
|
||||
* whose path is equal to entry.path. If entry is null then
|
||||
* all entries with the same pkey should be removed.
|
||||
*/
|
||||
public void remove (String pkey, AuthCacheValue entry);
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheImpl.java
Normal file
108
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheImpl.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* @author Michael McMahon
|
||||
*/
|
||||
|
||||
public class AuthCacheImpl implements AuthCache {
|
||||
HashMap<String,LinkedList<AuthCacheValue>> hashtable;
|
||||
|
||||
public AuthCacheImpl () {
|
||||
hashtable = new HashMap<String,LinkedList<AuthCacheValue>>();
|
||||
}
|
||||
|
||||
public void setMap (HashMap<String,LinkedList<AuthCacheValue>> map) {
|
||||
hashtable = map;
|
||||
}
|
||||
|
||||
// put a value in map according to primary key + secondary key which
|
||||
// is the path field of AuthenticationInfo
|
||||
|
||||
public synchronized void put (String pkey, AuthCacheValue value) {
|
||||
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
|
||||
String skey = value.getPath();
|
||||
if (list == null) {
|
||||
list = new LinkedList<AuthCacheValue>();
|
||||
hashtable.put(pkey, list);
|
||||
}
|
||||
// Check if the path already exists or a super-set of it exists
|
||||
ListIterator<AuthCacheValue> iter = list.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
|
||||
if (inf.path == null || inf.path.startsWith (skey)) {
|
||||
iter.remove ();
|
||||
}
|
||||
}
|
||||
iter.add(value);
|
||||
}
|
||||
|
||||
// get a value from map checking both primary
|
||||
// and secondary (urlpath) key
|
||||
|
||||
public synchronized AuthCacheValue get (String pkey, String skey) {
|
||||
AuthenticationInfo result = null;
|
||||
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
|
||||
if (list == null || list.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
if (skey == null) {
|
||||
// list should contain only one element
|
||||
return (AuthenticationInfo)list.get (0);
|
||||
}
|
||||
ListIterator<AuthCacheValue> iter = list.listIterator();
|
||||
while (iter.hasNext()) {
|
||||
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
|
||||
if (skey.startsWith (inf.path)) {
|
||||
return inf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public synchronized void remove (String pkey, AuthCacheValue entry) {
|
||||
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
if (entry == null) {
|
||||
list.clear();
|
||||
return;
|
||||
}
|
||||
ListIterator<AuthCacheValue> iter = list.listIterator ();
|
||||
while (iter.hasNext()) {
|
||||
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
|
||||
if (entry.equals(inf)) {
|
||||
iter.remove ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
100
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheValue.java
Normal file
100
jdkSrc/jdk8/sun/net/www/protocol/http/AuthCacheValue.java
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.PasswordAuthentication;
|
||||
|
||||
/**
|
||||
* AuthCacheValue: interface to minimize exposure to authentication cache
|
||||
* for external users (ie. plugin)
|
||||
*
|
||||
* @author Michael McMahon
|
||||
*/
|
||||
|
||||
public abstract class AuthCacheValue implements Serializable {
|
||||
|
||||
static final long serialVersionUID = 735249334068211611L;
|
||||
|
||||
public enum Type {
|
||||
Proxy,
|
||||
Server
|
||||
};
|
||||
|
||||
/**
|
||||
* Caches authentication info entered by user. See cacheKey()
|
||||
*/
|
||||
static protected AuthCache cache = new AuthCacheImpl();
|
||||
|
||||
public static void setAuthCache (AuthCache map) {
|
||||
cache = map;
|
||||
}
|
||||
|
||||
/* Package private ctor to prevent extension outside package */
|
||||
|
||||
AuthCacheValue() {}
|
||||
|
||||
/**
|
||||
* Proxy or Server
|
||||
*/
|
||||
abstract Type getAuthType ();
|
||||
|
||||
/**
|
||||
* Authentication scheme
|
||||
*/
|
||||
abstract AuthScheme getAuthScheme();
|
||||
|
||||
/**
|
||||
* name of server/proxy
|
||||
*/
|
||||
abstract String getHost ();
|
||||
|
||||
/**
|
||||
* portnumber of server/proxy
|
||||
*/
|
||||
abstract int getPort();
|
||||
|
||||
/**
|
||||
* realm of authentication if known
|
||||
*/
|
||||
abstract String getRealm();
|
||||
|
||||
/**
|
||||
* root path of realm or the request path if the root
|
||||
* is not known yet.
|
||||
*/
|
||||
abstract String getPath();
|
||||
|
||||
/**
|
||||
* returns http or https
|
||||
*/
|
||||
abstract String getProtocolScheme();
|
||||
|
||||
/**
|
||||
* the credentials associated with this authentication
|
||||
*/
|
||||
abstract PasswordAuthentication credentials();
|
||||
}
|
||||
38
jdkSrc/jdk8/sun/net/www/protocol/http/AuthScheme.java
Normal file
38
jdkSrc/jdk8/sun/net/www/protocol/http/AuthScheme.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
/* Authentication schemes supported by the http implementation. New schemes, if
|
||||
* supported, should be defined here.
|
||||
*/
|
||||
public enum AuthScheme {
|
||||
BASIC,
|
||||
DIGEST,
|
||||
NTLM,
|
||||
NEGOTIATE,
|
||||
KERBEROS,
|
||||
UNKNOWN;
|
||||
}
|
||||
|
||||
279
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationHeader.java
Normal file
279
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationHeader.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import sun.net.www.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class is used to parse the information in WWW-Authenticate: and Proxy-Authenticate:
|
||||
* headers. It searches among multiple header lines and within each header line
|
||||
* for the best currently supported scheme. It can also return a HeaderParser
|
||||
* containing the challenge data for that particular scheme.
|
||||
*
|
||||
* Some examples:
|
||||
*
|
||||
* WWW-Authenticate: Basic realm="foo" Digest realm="bar" NTLM
|
||||
* Note the realm parameter must be associated with the particular scheme.
|
||||
*
|
||||
* or
|
||||
*
|
||||
* WWW-Authenticate: Basic realm="foo"
|
||||
* WWW-Authenticate: Digest realm="foo",qop="auth",nonce="thisisanunlikelynonce"
|
||||
* WWW-Authenticate: NTLM
|
||||
*
|
||||
* or
|
||||
*
|
||||
* WWW-Authenticate: Basic realm="foo"
|
||||
* WWW-Authenticate: NTLM ASKAJK9893289889QWQIOIONMNMN
|
||||
*
|
||||
* The last example shows how NTLM breaks the rules of rfc2617 for the structure of
|
||||
* the authentication header. This is the reason why the raw header field is used for ntlm.
|
||||
*
|
||||
* At present, the class chooses schemes in following order :
|
||||
* 1. Negotiate (if supported)
|
||||
* 2. Kerberos (if supported)
|
||||
* 3. Digest
|
||||
* 4. NTLM (if supported)
|
||||
* 5. Basic
|
||||
*
|
||||
* This choice can be modified by setting a system property:
|
||||
*
|
||||
* -Dhttp.auth.preference="scheme"
|
||||
*
|
||||
* which in this case, specifies that "scheme" should be used as the auth scheme when offered
|
||||
* disregarding the default prioritisation. If scheme is not offered, or explicitly
|
||||
* disabled, by {@code disabledSchemes}, then the default priority is used.
|
||||
*
|
||||
* Attention: when http.auth.preference is set as SPNEGO or Kerberos, it's actually "Negotiate
|
||||
* with SPNEGO" or "Negotiate with Kerberos", which means the user will prefer the Negotiate
|
||||
* scheme with GSS/SPNEGO or GSS/Kerberos mechanism.
|
||||
*
|
||||
* This also means that the real "Kerberos" scheme can never be set as a preference.
|
||||
*/
|
||||
|
||||
public class AuthenticationHeader {
|
||||
|
||||
MessageHeader rsp; // the response to be parsed
|
||||
HeaderParser preferred;
|
||||
String preferred_r; // raw Strings
|
||||
private final HttpCallerInfo hci; // un-schemed, need check
|
||||
|
||||
// When set true, do not use Negotiate even if the response
|
||||
// headers suggest so.
|
||||
boolean dontUseNegotiate = false;
|
||||
static String authPref=null;
|
||||
|
||||
public String toString() {
|
||||
return "AuthenticationHeader: prefer " + preferred_r;
|
||||
}
|
||||
|
||||
static {
|
||||
authPref = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("http.auth.preference"));
|
||||
|
||||
// http.auth.preference can be set to SPNEGO or Kerberos.
|
||||
// In fact they means "Negotiate with SPNEGO" and "Negotiate with
|
||||
// Kerberos" separately, so here they are all translated into
|
||||
// Negotiate. Read NegotiateAuthentication.java to see how they
|
||||
// were used later.
|
||||
|
||||
if (authPref != null) {
|
||||
authPref = authPref.toLowerCase();
|
||||
if(authPref.equals("spnego") || authPref.equals("kerberos")) {
|
||||
authPref = "negotiate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String hdrname; // Name of the header to look for
|
||||
|
||||
/**
|
||||
* Parses a set of authentication headers and chooses the preferred scheme
|
||||
* that is supported for a given host.
|
||||
*/
|
||||
public AuthenticationHeader (String hdrname, MessageHeader response,
|
||||
HttpCallerInfo hci, boolean dontUseNegotiate) {
|
||||
this(hdrname, response, hci, dontUseNegotiate, Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a set of authentication headers and chooses the preferred scheme
|
||||
* that is supported for a given host.
|
||||
*
|
||||
* <p> The {@code disabledSchemes} parameter is a, possibly empty, set of
|
||||
* authentication schemes that are disabled.
|
||||
*/
|
||||
public AuthenticationHeader(String hdrname,
|
||||
MessageHeader response,
|
||||
HttpCallerInfo hci,
|
||||
boolean dontUseNegotiate,
|
||||
Set<String> disabledSchemes) {
|
||||
this.hci = hci;
|
||||
this.dontUseNegotiate = dontUseNegotiate;
|
||||
this.rsp = response;
|
||||
this.hdrname = hdrname;
|
||||
this.schemes = new HashMap<>();
|
||||
parse(disabledSchemes);
|
||||
}
|
||||
|
||||
public HttpCallerInfo getHttpCallerInfo() {
|
||||
return hci;
|
||||
}
|
||||
/* we build up a map of scheme names mapped to SchemeMapValue objects */
|
||||
static class SchemeMapValue {
|
||||
SchemeMapValue (HeaderParser h, String r) {raw=r; parser=h;}
|
||||
String raw;
|
||||
HeaderParser parser;
|
||||
}
|
||||
|
||||
HashMap<String, SchemeMapValue> schemes;
|
||||
|
||||
/* Iterate through each header line, and then within each line.
|
||||
* If multiple entries exist for a particular scheme (unlikely)
|
||||
* then the last one will be used. The
|
||||
* preferred scheme that we support will be used.
|
||||
*/
|
||||
private void parse(Set<String> disabledSchemes) {
|
||||
Iterator<String> iter = rsp.multiValueIterator(hdrname);
|
||||
while (iter.hasNext()) {
|
||||
String raw = iter.next();
|
||||
// HeaderParser lower cases everything, so can be used case-insensitively
|
||||
HeaderParser hp = new HeaderParser(raw);
|
||||
Iterator<String> keys = hp.keys();
|
||||
int i, lastSchemeIndex;
|
||||
for (i=0, lastSchemeIndex = -1; keys.hasNext(); i++) {
|
||||
keys.next();
|
||||
if (hp.findValue(i) == null) { /* found a scheme name */
|
||||
if (lastSchemeIndex != -1) {
|
||||
HeaderParser hpn = hp.subsequence (lastSchemeIndex, i);
|
||||
String scheme = hpn.findKey(0);
|
||||
if (!disabledSchemes.contains(scheme))
|
||||
schemes.put (scheme, new SchemeMapValue (hpn, raw));
|
||||
}
|
||||
lastSchemeIndex = i;
|
||||
}
|
||||
}
|
||||
if (i > lastSchemeIndex) {
|
||||
HeaderParser hpn = hp.subsequence (lastSchemeIndex, i);
|
||||
String scheme = hpn.findKey(0);
|
||||
if (!disabledSchemes.contains(scheme))
|
||||
schemes.put(scheme, new SchemeMapValue (hpn, raw));
|
||||
}
|
||||
}
|
||||
|
||||
/* choose the best of them, the order is
|
||||
* negotiate -> kerberos -> digest -> ntlm -> basic
|
||||
*/
|
||||
SchemeMapValue v = null;
|
||||
if (authPref == null || (v=schemes.get (authPref)) == null) {
|
||||
|
||||
if(v == null && !dontUseNegotiate) {
|
||||
SchemeMapValue tmp = schemes.get("negotiate");
|
||||
if(tmp != null) {
|
||||
if(hci == null || !NegotiateAuthentication.isSupported(new HttpCallerInfo(hci, "Negotiate"))) {
|
||||
tmp = null;
|
||||
}
|
||||
v = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if(v == null && !dontUseNegotiate) {
|
||||
SchemeMapValue tmp = schemes.get("kerberos");
|
||||
if(tmp != null) {
|
||||
// the Kerberos scheme is only observed in MS ISA Server. In
|
||||
// fact i think it's a Kerberos-mechnism-only Negotiate.
|
||||
// Since the Kerberos scheme is always accompanied with the
|
||||
// Negotiate scheme, so it seems impossible to reach this
|
||||
// line. Even if the user explicitly set http.auth.preference
|
||||
// as Kerberos, it means Negotiate with Kerberos, and the code
|
||||
// will still tried to use Negotiate at first.
|
||||
//
|
||||
// The only chance this line get executed is that the server
|
||||
// only suggest the Kerberos scheme.
|
||||
if(hci == null || !NegotiateAuthentication.isSupported(new HttpCallerInfo(hci, "Kerberos"))) {
|
||||
tmp = null;
|
||||
}
|
||||
v = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if(v == null) {
|
||||
if ((v=schemes.get ("digest")) == null) {
|
||||
if (!NTLMAuthenticationProxy.supported
|
||||
|| ((v=schemes.get("ntlm"))==null)) {
|
||||
v = schemes.get ("basic");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // authPref != null && it's found in reponses'
|
||||
if (dontUseNegotiate && authPref.equals("negotiate")) {
|
||||
v = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (v != null) {
|
||||
preferred = v.parser;
|
||||
preferred_r = v.raw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return a header parser containing the preferred authentication scheme (only).
|
||||
* The preferred scheme is the strongest of the schemes proposed by the server.
|
||||
* The returned HeaderParser will contain the relevant parameters for that scheme
|
||||
*/
|
||||
public HeaderParser headerParser() {
|
||||
return preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the name of the preferred scheme
|
||||
*/
|
||||
public String scheme() {
|
||||
if (preferred != null) {
|
||||
return preferred.findKey(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the raw header field for the preferred/chosen scheme */
|
||||
|
||||
public String raw () {
|
||||
return preferred_r;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true is the header exists and contains a recognised scheme
|
||||
*/
|
||||
public boolean isPresent () {
|
||||
return preferred != null;
|
||||
}
|
||||
}
|
||||
463
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationInfo.java
Normal file
463
jdkSrc/jdk8/sun/net/www/protocol/http/AuthenticationInfo.java
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* AuthenticationInfo: Encapsulate the information needed to
|
||||
* authenticate a user to a server.
|
||||
*
|
||||
* @author Jon Payne
|
||||
* @author Herb Jellinek
|
||||
* @author Bill Foote
|
||||
*/
|
||||
// REMIND: It would be nice if this class understood about partial matching.
|
||||
// If you're authorized for foo.com, chances are high you're also
|
||||
// authorized for baz.foo.com.
|
||||
// NB: When this gets implemented, be careful about the uncaching
|
||||
// policy in HttpURLConnection. A failure on baz.foo.com shouldn't
|
||||
// uncache foo.com!
|
||||
|
||||
public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
|
||||
static final long serialVersionUID = -2588378268010453259L;
|
||||
|
||||
// Constants saying what kind of authroization this is. This determines
|
||||
// the namespace in the hash table lookup.
|
||||
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
|
||||
* are serialized, in order to avoid a user having to type the same username/passwords
|
||||
* repeatedly, via the Authenticator. Default is false, which means that this
|
||||
* behavior is switched off.
|
||||
*/
|
||||
static final boolean serializeAuth;
|
||||
static {
|
||||
serializeAuth = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction(
|
||||
"http.auth.serializeRequests")).booleanValue();
|
||||
}
|
||||
|
||||
/* AuthCacheValue: */
|
||||
|
||||
transient protected PasswordAuthentication pw;
|
||||
|
||||
public PasswordAuthentication credentials() {
|
||||
return pw;
|
||||
}
|
||||
|
||||
public AuthCacheValue.Type getAuthType() {
|
||||
return type == SERVER_AUTHENTICATION ?
|
||||
AuthCacheValue.Type.Server:
|
||||
AuthCacheValue.Type.Proxy;
|
||||
}
|
||||
|
||||
AuthScheme getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
public String getProtocolScheme() {
|
||||
return protocol;
|
||||
}
|
||||
/**
|
||||
* Whether we should cache this instance in the AuthCache.
|
||||
* This method returns {@code true} by default.
|
||||
* Subclasses may override this method to add
|
||||
* additional restrictions.
|
||||
* @return {@code true} by default.
|
||||
*/
|
||||
protected boolean useAuthCache() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* requests is used to ensure that interaction with the
|
||||
* Authenticator for a particular realm is single threaded.
|
||||
* ie. if multiple threads need to get credentials from the user
|
||||
* at the same time, then all but the first will block until
|
||||
* the first completes its authentication.
|
||||
*/
|
||||
static private HashMap<String,Thread> requests = new HashMap<>();
|
||||
|
||||
/* check if a request for this destination is in progress
|
||||
* return false immediately if not. Otherwise block until
|
||||
* request is finished and return true
|
||||
*/
|
||||
static private boolean requestIsInProgress (String key) {
|
||||
if (!serializeAuth) {
|
||||
/* behavior is disabled. Revert to concurrent requests */
|
||||
return false;
|
||||
}
|
||||
synchronized (requests) {
|
||||
Thread t, c;
|
||||
c = Thread.currentThread();
|
||||
if ((t = requests.get(key)) == null) {
|
||||
requests.put (key, c);
|
||||
return false;
|
||||
}
|
||||
if (t == c) {
|
||||
return false;
|
||||
}
|
||||
while (requests.containsKey(key)) {
|
||||
try {
|
||||
requests.wait ();
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
/* entry may be in cache now. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* signal completion of an authentication (whether it succeeded or not)
|
||||
* so that other threads can continue.
|
||||
*/
|
||||
static private void requestCompleted (String key) {
|
||||
synchronized (requests) {
|
||||
Thread thread = requests.get(key);
|
||||
if (thread != null && thread == Thread.currentThread()) {
|
||||
boolean waspresent = requests.remove(key) != null;
|
||||
assert waspresent;
|
||||
}
|
||||
requests.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
//public String toString () {
|
||||
//return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
|
||||
//}
|
||||
|
||||
// REMIND: This cache just grows forever. We should put in a bounded
|
||||
// cache, or maybe something using WeakRef's.
|
||||
|
||||
/** The type (server/proxy) of authentication this is. Used for key lookup */
|
||||
char type;
|
||||
|
||||
/** The authentication scheme (basic/digest). Also used for key lookup */
|
||||
AuthScheme authScheme;
|
||||
|
||||
/** The protocol/scheme (i.e. http or https ). Need to keep the caches
|
||||
* logically separate for the two protocols. This field is only used
|
||||
* when constructed with a URL (the normal case for server authentication)
|
||||
* For proxy authentication the protocol is not relevant.
|
||||
*/
|
||||
String protocol;
|
||||
|
||||
/** The host we're authenticating against. */
|
||||
String host;
|
||||
|
||||
/** The port on the host we're authenticating against. */
|
||||
int port;
|
||||
|
||||
/** The realm we're authenticating against. */
|
||||
String realm;
|
||||
|
||||
/** The shortest path from the URL we authenticated against. */
|
||||
String path;
|
||||
|
||||
/** Use this constructor only for proxy entries */
|
||||
public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
|
||||
this.type = type;
|
||||
this.authScheme = authScheme;
|
||||
this.protocol = "";
|
||||
this.host = host.toLowerCase();
|
||||
this.port = port;
|
||||
this.realm = realm;
|
||||
this.path = null;
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone ();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// Cannot happen because Cloneable implemented by AuthenticationInfo
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor used to limit the authorization to the path within
|
||||
* the URL. Use this constructor for origin server entries.
|
||||
*/
|
||||
public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
|
||||
this.type = type;
|
||||
this.authScheme = authScheme;
|
||||
this.protocol = url.getProtocol().toLowerCase();
|
||||
this.host = url.getHost().toLowerCase();
|
||||
this.port = url.getPort();
|
||||
if (this.port == -1) {
|
||||
this.port = url.getDefaultPort();
|
||||
}
|
||||
this.realm = realm;
|
||||
|
||||
String urlPath = url.getPath();
|
||||
if (urlPath.length() == 0)
|
||||
this.path = urlPath;
|
||||
else {
|
||||
this.path = reducePath (urlPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* reduce the path to the root of where we think the
|
||||
* authorization begins. This could get shorter as
|
||||
* the url is traversed up following a successful challenge.
|
||||
*/
|
||||
static String reducePath (String urlPath) {
|
||||
int sepIndex = urlPath.lastIndexOf('/');
|
||||
int targetSuffixIndex = urlPath.lastIndexOf('.');
|
||||
if (sepIndex != -1)
|
||||
if (sepIndex < targetSuffixIndex)
|
||||
return urlPath.substring(0, sepIndex+1);
|
||||
else
|
||||
return urlPath;
|
||||
else
|
||||
return urlPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info for the URL, for an HTTP server auth. Used when we
|
||||
* don't yet know the realm
|
||||
* (i.e. when we're preemptively setting the auth).
|
||||
*/
|
||||
static AuthenticationInfo getServerAuth(URL url) {
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
port = url.getDefaultPort();
|
||||
}
|
||||
String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
|
||||
+ ":" + url.getHost().toLowerCase() + ":" + port;
|
||||
return getAuth(key, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns info for the URL, for an HTTP server auth. Used when we
|
||||
* do know the realm (i.e. when we're responding to a challenge).
|
||||
* In this case we do not use the path because the protection space
|
||||
* is identified by the host:port:realm only
|
||||
*/
|
||||
static String getServerAuthKey(URL url, String realm, AuthScheme scheme) {
|
||||
int port = url.getPort();
|
||||
if (port == -1) {
|
||||
port = url.getDefaultPort();
|
||||
}
|
||||
String key = SERVER_AUTHENTICATION + ":" + scheme + ":" + url.getProtocol().toLowerCase()
|
||||
+ ":" + url.getHost().toLowerCase() + ":" + port + ":" + realm;
|
||||
return key;
|
||||
}
|
||||
|
||||
static AuthenticationInfo getServerAuth(String key) {
|
||||
AuthenticationInfo cached = getAuth(key, null);
|
||||
if ((cached == null) && requestIsInProgress (key)) {
|
||||
/* check the cache again, it might contain an entry */
|
||||
cached = getAuth(key, null);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the AuthenticationInfo object from the cache if it's path is
|
||||
* a substring of the supplied URLs path.
|
||||
*/
|
||||
static AuthenticationInfo getAuth(String key, URL url) {
|
||||
if (url == null) {
|
||||
return (AuthenticationInfo)cache.get (key, null);
|
||||
} else {
|
||||
return (AuthenticationInfo)cache.get (key, url.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a firewall authentication, for the given host/port. Used
|
||||
* for preemptive header-setting. Note, the protocol field is always
|
||||
* blank for proxies.
|
||||
*/
|
||||
static AuthenticationInfo getProxyAuth(String host, int port) {
|
||||
String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port;
|
||||
AuthenticationInfo result = (AuthenticationInfo) cache.get(key, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a firewall authentication, for the given host/port and realm.
|
||||
* Used in response to a challenge. Note, the protocol field is always
|
||||
* blank for proxies.
|
||||
*/
|
||||
static String getProxyAuthKey(String host, int port, String realm, AuthScheme scheme) {
|
||||
String key = PROXY_AUTHENTICATION + ":" + scheme + "::" + host.toLowerCase()
|
||||
+ ":" + port + ":" + realm;
|
||||
return key;
|
||||
}
|
||||
|
||||
static AuthenticationInfo getProxyAuth(String key) {
|
||||
AuthenticationInfo cached = (AuthenticationInfo) cache.get(key, null);
|
||||
if ((cached == null) && requestIsInProgress (key)) {
|
||||
/* check the cache again, it might contain an entry */
|
||||
cached = (AuthenticationInfo) cache.get(key, null);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add this authentication to the cache
|
||||
*/
|
||||
void addToCache() {
|
||||
String key = cacheKey(true);
|
||||
if (useAuthCache()) {
|
||||
cache.put(key, this);
|
||||
if (supportsPreemptiveAuthorization()) {
|
||||
cache.put(cacheKey(false), this);
|
||||
}
|
||||
}
|
||||
endAuthRequest(key);
|
||||
}
|
||||
|
||||
static void endAuthRequest (String key) {
|
||||
if (!serializeAuth) {
|
||||
return;
|
||||
}
|
||||
synchronized (requests) {
|
||||
requestCompleted(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this authentication from the cache
|
||||
*/
|
||||
void removeFromCache() {
|
||||
cache.remove(cacheKey(true), this);
|
||||
if (supportsPreemptiveAuthorization()) {
|
||||
cache.remove(cacheKey(false), this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
public abstract boolean supportsPreemptiveAuthorization();
|
||||
|
||||
/**
|
||||
* @return the name of the HTTP header this authentication wants set.
|
||||
* This is used for preemptive authorization.
|
||||
*/
|
||||
public String getHeaderName() {
|
||||
if (type == SERVER_AUTHENTICATION) {
|
||||
return "Authorization";
|
||||
} else {
|
||||
return "Proxy-authorization";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates and returns the authentication header value based
|
||||
* on the stored authentication parameters. If the calculation does not depend
|
||||
* on the URL or the request method then these parameters are ignored.
|
||||
* @param url The URL
|
||||
* @param method The request method
|
||||
* @return the value of the HTTP header this authentication wants set.
|
||||
* Used for preemptive authorization.
|
||||
*/
|
||||
public abstract String getHeaderValue(URL url, String method);
|
||||
|
||||
/**
|
||||
* Set header(s) on the given connection. Subclasses must override
|
||||
* This will only be called for
|
||||
* definitive (i.e. non-preemptive) authorization.
|
||||
* @param conn The connection to apply the header(s) to
|
||||
* @param p A source of header values for this connection, if needed.
|
||||
* @param raw The raw header field (if needed)
|
||||
* @return true if all goes well, false if no headers were set.
|
||||
*/
|
||||
public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public abstract boolean isAuthorizationStale (String header);
|
||||
|
||||
/**
|
||||
* Give a key for hash table lookups.
|
||||
* @param includeRealm if you want the realm considered. Preemptively
|
||||
* setting an authorization is done before the realm is known.
|
||||
*/
|
||||
String cacheKey(boolean includeRealm) {
|
||||
// This must be kept in sync with the getXXXAuth() methods in this
|
||||
// class.
|
||||
if (includeRealm) {
|
||||
return type + ":" + authScheme + ":" + protocol + ":"
|
||||
+ host + ":" + port + ":" + realm;
|
||||
} else {
|
||||
return type + ":" + protocol + ":" + host + ":" + port;
|
||||
}
|
||||
}
|
||||
|
||||
String s1, s2; /* used for serialization of pw */
|
||||
|
||||
private void readObject(ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
s.defaultReadObject ();
|
||||
pw = new PasswordAuthentication (s1, s2.toCharArray());
|
||||
s1 = null; s2= null;
|
||||
}
|
||||
|
||||
private synchronized void writeObject(java.io.ObjectOutputStream s)
|
||||
throws IOException
|
||||
{
|
||||
s1 = pw.getUserName();
|
||||
s2 = new String (pw.getPassword());
|
||||
s.defaultWriteObject ();
|
||||
}
|
||||
}
|
||||
205
jdkSrc/jdk8/sun/net/www/protocol/http/BasicAuthentication.java
Normal file
205
jdkSrc/jdk8/sun/net/www/protocol/http/BasicAuthentication.java
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Base64;
|
||||
import sun.net.www.HeaderParser;
|
||||
|
||||
/**
|
||||
* BasicAuthentication: Encapsulate an http server authentication using
|
||||
* the "basic" scheme.
|
||||
*
|
||||
* @author Bill Foote
|
||||
*/
|
||||
|
||||
|
||||
class BasicAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
/** The authentication string for this host, port, and realm. This is
|
||||
a simple BASE64 encoding of "login:password". */
|
||||
String auth;
|
||||
|
||||
/**
|
||||
* Create a BasicAuthentication
|
||||
*/
|
||||
public BasicAuthentication(boolean isProxy, String host, int port,
|
||||
String realm, PasswordAuthentication pw) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, host, port, realm);
|
||||
String plain = pw.getUserName() + ":";
|
||||
byte[] nameBytes = null;
|
||||
try {
|
||||
nameBytes = plain.getBytes("ISO-8859-1");
|
||||
} catch (java.io.UnsupportedEncodingException uee) {
|
||||
assert false;
|
||||
}
|
||||
|
||||
// get password bytes
|
||||
char[] passwd = pw.getPassword();
|
||||
byte[] passwdBytes = new byte[passwd.length];
|
||||
for (int i=0; i<passwd.length; i++)
|
||||
passwdBytes[i] = (byte)passwd[i];
|
||||
|
||||
// concatenate user name and password bytes and encode them
|
||||
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
|
||||
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
|
||||
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
|
||||
passwdBytes.length);
|
||||
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
|
||||
this.pw = pw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BasicAuthentication
|
||||
*/
|
||||
public BasicAuthentication(boolean isProxy, String host, int port,
|
||||
String realm, String auth) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, host, port, realm);
|
||||
this.auth = "Basic " + auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BasicAuthentication
|
||||
*/
|
||||
public BasicAuthentication(boolean isProxy, URL url, String realm,
|
||||
PasswordAuthentication pw) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, url, realm);
|
||||
String plain = pw.getUserName() + ":";
|
||||
byte[] nameBytes = null;
|
||||
try {
|
||||
nameBytes = plain.getBytes("ISO-8859-1");
|
||||
} catch (java.io.UnsupportedEncodingException uee) {
|
||||
assert false;
|
||||
}
|
||||
|
||||
// get password bytes
|
||||
char[] passwd = pw.getPassword();
|
||||
byte[] passwdBytes = new byte[passwd.length];
|
||||
for (int i=0; i<passwd.length; i++)
|
||||
passwdBytes[i] = (byte)passwd[i];
|
||||
|
||||
// concatenate user name and password bytes and encode them
|
||||
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
|
||||
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
|
||||
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
|
||||
passwdBytes.length);
|
||||
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
|
||||
this.pw = pw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a BasicAuthentication
|
||||
*/
|
||||
public BasicAuthentication(boolean isProxy, URL url, String realm,
|
||||
String auth) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.BASIC, url, realm);
|
||||
this.auth = "Basic " + auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set header(s) on the given connection. This will only be called for
|
||||
* definitive (i.e. non-preemptive) authorization.
|
||||
* @param conn The connection to apply the header(s) to
|
||||
* @param p A source of header values for this connection, if needed.
|
||||
* @param raw The raw header values for this connection, if needed.
|
||||
* @return true if all goes well, false if no headers were set.
|
||||
*/
|
||||
@Override
|
||||
public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
|
||||
conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value of the HTTP header this authentication wants set
|
||||
*/
|
||||
@Override
|
||||
public String getHeaderValue(URL url, String method) {
|
||||
/* For Basic the authorization string does not depend on the request URL
|
||||
* or the request method
|
||||
*/
|
||||
return auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* For Basic Authentication, the security parameters can never be stale.
|
||||
* In other words there is no possibility to reuse the credentials.
|
||||
* They are always either valid or invalid.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAuthorizationStale (String header) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the common root path between npath and path.
|
||||
* This is used to detect when we have an authentication for two
|
||||
* paths and the root of th authentication space is the common root.
|
||||
*/
|
||||
|
||||
static String getRootPath(String npath, String opath) {
|
||||
int index = 0;
|
||||
int toindex;
|
||||
|
||||
/* Must normalize so we don't get confused by ../ and ./ segments */
|
||||
try {
|
||||
npath = new URI (npath).normalize().getPath();
|
||||
opath = new URI (opath).normalize().getPath();
|
||||
} catch (URISyntaxException e) {
|
||||
/* ignore error and use the old value */
|
||||
}
|
||||
|
||||
while (index < opath.length()) {
|
||||
toindex = opath.indexOf('/', index+1);
|
||||
if (toindex != -1 && opath.regionMatches(0, npath, 0, toindex+1))
|
||||
index = toindex;
|
||||
else
|
||||
return opath.substring(0, index+1);
|
||||
}
|
||||
/*should not reach here. If we do simply return npath*/
|
||||
return npath;
|
||||
}
|
||||
}
|
||||
|
||||
544
jdkSrc/jdk8/sun/net/www/protocol/http/DigestAuthentication.java
Normal file
544
jdkSrc/jdk8/sun/net/www/protocol/http/DigestAuthentication.java
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.Arrays;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Random;
|
||||
|
||||
import sun.net.www.HeaderParser;
|
||||
import sun.net.NetProperties;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.AccessController;
|
||||
import static sun.net.www.protocol.http.HttpURLConnection.HTTP_CONNECT;
|
||||
|
||||
/**
|
||||
* DigestAuthentication: Encapsulate an http server authentication using
|
||||
* the "Digest" scheme, as described in RFC2069 and updated in RFC2617
|
||||
*
|
||||
* @author Bill Foote
|
||||
*/
|
||||
|
||||
class DigestAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
private String authMethod;
|
||||
|
||||
private final static String compatPropName = "http.auth.digest." +
|
||||
"quoteParameters";
|
||||
|
||||
// true if http.auth.digest.quoteParameters Net property is true
|
||||
private static final boolean delimCompatFlag;
|
||||
|
||||
static {
|
||||
Boolean b = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return NetProperties.getBoolean(compatPropName);
|
||||
}
|
||||
}
|
||||
);
|
||||
delimCompatFlag = (b == null) ? false : b.booleanValue();
|
||||
}
|
||||
|
||||
// Authentication parameters defined in RFC2617.
|
||||
// One instance of these may be shared among several DigestAuthentication
|
||||
// instances as a result of a single authorization (for multiple domains)
|
||||
|
||||
static class Parameters implements java.io.Serializable {
|
||||
private static final long serialVersionUID = -3584543755194526252L;
|
||||
|
||||
private boolean serverQop; // server proposed qop=auth
|
||||
private String opaque;
|
||||
private String cnonce;
|
||||
private String nonce;
|
||||
private String algorithm;
|
||||
private int NCcount=0;
|
||||
|
||||
// The H(A1) string used for MD5-sess
|
||||
private String cachedHA1;
|
||||
|
||||
// Force the HA1 value to be recalculated because the nonce has changed
|
||||
private boolean redoCachedHA1 = true;
|
||||
|
||||
private static final int cnonceRepeat = 5;
|
||||
|
||||
private static final int cnoncelen = 40; /* number of characters in cnonce */
|
||||
|
||||
private static Random random;
|
||||
|
||||
static {
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
Parameters () {
|
||||
serverQop = false;
|
||||
opaque = null;
|
||||
algorithm = null;
|
||||
cachedHA1 = null;
|
||||
nonce = null;
|
||||
setNewCnonce();
|
||||
}
|
||||
|
||||
boolean authQop () {
|
||||
return serverQop;
|
||||
}
|
||||
synchronized void incrementNC() {
|
||||
NCcount ++;
|
||||
}
|
||||
synchronized int getNCCount () {
|
||||
return NCcount;
|
||||
}
|
||||
|
||||
int cnonce_count = 0;
|
||||
|
||||
/* each call increments the counter */
|
||||
synchronized String getCnonce () {
|
||||
if (cnonce_count >= cnonceRepeat) {
|
||||
setNewCnonce();
|
||||
}
|
||||
cnonce_count++;
|
||||
return cnonce;
|
||||
}
|
||||
synchronized void setNewCnonce () {
|
||||
byte bb[] = new byte [cnoncelen/2];
|
||||
char cc[] = new char [cnoncelen];
|
||||
random.nextBytes (bb);
|
||||
for (int i=0; i<(cnoncelen/2); i++) {
|
||||
int x = bb[i] + 128;
|
||||
cc[i*2]= (char) ('A'+ x/16);
|
||||
cc[i*2+1]= (char) ('A'+ x%16);
|
||||
}
|
||||
cnonce = new String (cc, 0, cnoncelen);
|
||||
cnonce_count = 0;
|
||||
redoCachedHA1 = true;
|
||||
}
|
||||
|
||||
synchronized void setQop (String qop) {
|
||||
if (qop != null) {
|
||||
StringTokenizer st = new StringTokenizer (qop, " ");
|
||||
while (st.hasMoreTokens()) {
|
||||
if (st.nextToken().equalsIgnoreCase ("auth")) {
|
||||
serverQop = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
serverQop = false;
|
||||
}
|
||||
|
||||
synchronized String getOpaque () { return opaque;}
|
||||
synchronized void setOpaque (String s) { opaque=s;}
|
||||
|
||||
synchronized String getNonce () { return nonce;}
|
||||
|
||||
synchronized void setNonce (String s) {
|
||||
if (!s.equals(nonce)) {
|
||||
nonce=s;
|
||||
NCcount = 0;
|
||||
redoCachedHA1 = true;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized String getCachedHA1 () {
|
||||
if (redoCachedHA1) {
|
||||
return null;
|
||||
} else {
|
||||
return cachedHA1;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void setCachedHA1 (String s) {
|
||||
cachedHA1=s;
|
||||
redoCachedHA1=false;
|
||||
}
|
||||
|
||||
synchronized String getAlgorithm () { return algorithm;}
|
||||
synchronized void setAlgorithm (String s) { algorithm=s;}
|
||||
}
|
||||
|
||||
Parameters params;
|
||||
|
||||
/**
|
||||
* Create a DigestAuthentication
|
||||
*/
|
||||
public DigestAuthentication(boolean isProxy, URL url, String realm,
|
||||
String authMethod, PasswordAuthentication pw,
|
||||
Parameters params) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.DIGEST,
|
||||
url,
|
||||
realm);
|
||||
this.authMethod = authMethod;
|
||||
this.pw = pw;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public DigestAuthentication(boolean isProxy, String host, int port, String realm,
|
||||
String authMethod, PasswordAuthentication pw,
|
||||
Parameters params) {
|
||||
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
AuthScheme.DIGEST,
|
||||
host,
|
||||
port,
|
||||
realm);
|
||||
this.authMethod = authMethod;
|
||||
this.pw = pw;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaculates the request-digest and returns it.
|
||||
*
|
||||
* <P> Used in the common case where the requestURI is simply the
|
||||
* abs_path.
|
||||
*
|
||||
* @param url
|
||||
* the URL
|
||||
*
|
||||
* @param method
|
||||
* the HTTP method
|
||||
*
|
||||
* @return the value of the HTTP header this authentication wants set
|
||||
*/
|
||||
@Override
|
||||
public String getHeaderValue(URL url, String method) {
|
||||
return getHeaderValueImpl(url.getFile(), method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reclaculates the request-digest and returns it.
|
||||
*
|
||||
* <P> Used when the requestURI is not the abs_path. The exact
|
||||
* requestURI can be passed as a String.
|
||||
*
|
||||
* @param requestURI
|
||||
* the Request-URI from the HTTP request line
|
||||
*
|
||||
* @param method
|
||||
* the HTTP method
|
||||
*
|
||||
* @return the value of the HTTP header this authentication wants set
|
||||
*/
|
||||
String getHeaderValue(String requestURI, String method) {
|
||||
return getHeaderValueImpl(requestURI, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
HeaderParser p = new HeaderParser (header);
|
||||
String s = p.findValue ("stale");
|
||||
if (s == null || !s.equals("true"))
|
||||
return false;
|
||||
String newNonce = p.findValue ("nonce");
|
||||
if (newNonce == null || "".equals(newNonce)) {
|
||||
return false;
|
||||
}
|
||||
params.setNonce (newNonce);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, if needed.
|
||||
* @param raw Raw header values for this connection, if needed.
|
||||
* @return true if all goes well, false if no headers were set.
|
||||
*/
|
||||
@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"));
|
||||
|
||||
String uri="";
|
||||
String method;
|
||||
if (type == PROXY_AUTHENTICATION &&
|
||||
conn.tunnelState() == HttpURLConnection.TunnelState.SETUP) {
|
||||
uri = HttpURLConnection.connectRequestURI(conn.getURL());
|
||||
method = HTTP_CONNECT;
|
||||
} else {
|
||||
try {
|
||||
uri = conn.getRequestURI();
|
||||
} catch (IOException e) {}
|
||||
method = conn.getMethod();
|
||||
}
|
||||
|
||||
if (params.nonce == null || authMethod == null || pw == null || realm == null) {
|
||||
return false;
|
||||
}
|
||||
if (authMethod.length() >= 1) {
|
||||
// Method seems to get converted to all lower case elsewhere.
|
||||
// It really does need to start with an upper case letter
|
||||
// here.
|
||||
authMethod = Character.toUpperCase(authMethod.charAt(0))
|
||||
+ authMethod.substring(1).toLowerCase();
|
||||
}
|
||||
String algorithm = p.findValue("algorithm");
|
||||
if (algorithm == null || "".equals(algorithm)) {
|
||||
algorithm = "MD5"; // The default, accoriding to rfc2069
|
||||
}
|
||||
params.setAlgorithm (algorithm);
|
||||
|
||||
// If authQop is true, then the server is doing RFC2617 and
|
||||
// has offered qop=auth. We do not support any other modes
|
||||
// and if auth is not offered we fallback to the RFC2069 behavior
|
||||
|
||||
if (params.authQop()) {
|
||||
params.setNewCnonce();
|
||||
}
|
||||
|
||||
String value = getHeaderValueImpl (uri, method);
|
||||
if (value != null) {
|
||||
conn.setAuthenticationProperty(getHeaderName(), value);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the Authorization header field given the request URI
|
||||
* and based on the authorization information in params
|
||||
*/
|
||||
private String getHeaderValueImpl (String uri, String method) {
|
||||
String response;
|
||||
char[] passwd = pw.getPassword();
|
||||
boolean qop = params.authQop();
|
||||
String opaque = params.getOpaque();
|
||||
String cnonce = params.getCnonce ();
|
||||
String nonce = params.getNonce ();
|
||||
String algorithm = params.getAlgorithm ();
|
||||
params.incrementNC ();
|
||||
int nccount = params.getNCCount ();
|
||||
String ncstring=null;
|
||||
|
||||
if (nccount != -1) {
|
||||
ncstring = Integer.toHexString (nccount).toLowerCase();
|
||||
int len = ncstring.length();
|
||||
if (len < 8)
|
||||
ncstring = zeroPad [len] + ncstring;
|
||||
}
|
||||
|
||||
try {
|
||||
response = computeDigest(true, pw.getUserName(),passwd,realm,
|
||||
method, uri, nonce, cnonce, ncstring);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String ncfield = "\"";
|
||||
if (qop) {
|
||||
ncfield = "\", nc=" + ncstring;
|
||||
}
|
||||
|
||||
String algoS, qopS;
|
||||
|
||||
if (delimCompatFlag) {
|
||||
// Put quotes around these String value parameters
|
||||
algoS = ", algorithm=\"" + algorithm + "\"";
|
||||
qopS = ", qop=\"auth\"";
|
||||
} else {
|
||||
// Don't put quotes around them, per the RFC
|
||||
algoS = ", algorithm=" + algorithm;
|
||||
qopS = ", qop=auth";
|
||||
}
|
||||
|
||||
String value = authMethod
|
||||
+ " username=\"" + pw.getUserName()
|
||||
+ "\", realm=\"" + realm
|
||||
+ "\", nonce=\"" + nonce
|
||||
+ ncfield
|
||||
+ ", uri=\"" + uri
|
||||
+ "\", response=\"" + response + "\""
|
||||
+ algoS;
|
||||
if (opaque != null) {
|
||||
value += ", opaque=\"" + opaque + "\"";
|
||||
}
|
||||
if (cnonce != null) {
|
||||
value += ", cnonce=\"" + cnonce + "\"";
|
||||
}
|
||||
if (qop) {
|
||||
value += qopS;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void checkResponse (String header, String method, URL url)
|
||||
throws IOException {
|
||||
checkResponse (header, method, url.getFile());
|
||||
}
|
||||
|
||||
public void checkResponse (String header, String method, String uri)
|
||||
throws IOException {
|
||||
char[] passwd = pw.getPassword();
|
||||
String username = pw.getUserName();
|
||||
boolean qop = params.authQop();
|
||||
String opaque = params.getOpaque();
|
||||
String cnonce = params.cnonce;
|
||||
String nonce = params.getNonce ();
|
||||
String algorithm = params.getAlgorithm ();
|
||||
int nccount = params.getNCCount ();
|
||||
String ncstring=null;
|
||||
|
||||
if (header == null) {
|
||||
throw new ProtocolException ("No authentication information in response");
|
||||
}
|
||||
|
||||
if (nccount != -1) {
|
||||
ncstring = Integer.toHexString (nccount).toUpperCase();
|
||||
int len = ncstring.length();
|
||||
if (len < 8)
|
||||
ncstring = zeroPad [len] + ncstring;
|
||||
}
|
||||
try {
|
||||
String expected = computeDigest(false, username,passwd,realm,
|
||||
method, uri, nonce, cnonce, ncstring);
|
||||
HeaderParser p = new HeaderParser (header);
|
||||
String rspauth = p.findValue ("rspauth");
|
||||
if (rspauth == null) {
|
||||
throw new ProtocolException ("No digest in response");
|
||||
}
|
||||
if (!rspauth.equals (expected)) {
|
||||
throw new ProtocolException ("Response digest invalid");
|
||||
}
|
||||
/* Check if there is a nextnonce field */
|
||||
String nextnonce = p.findValue ("nextnonce");
|
||||
if (nextnonce != null && ! "".equals(nextnonce)) {
|
||||
params.setNonce (nextnonce);
|
||||
}
|
||||
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new ProtocolException ("Unsupported algorithm in response");
|
||||
}
|
||||
}
|
||||
|
||||
private String computeDigest(
|
||||
boolean isRequest, String userName, char[] password,
|
||||
String realm, String connMethod,
|
||||
String requestURI, String nonceString,
|
||||
String cnonce, String ncValue
|
||||
) throws NoSuchAlgorithmException
|
||||
{
|
||||
|
||||
String A1, HashA1;
|
||||
String algorithm = params.getAlgorithm ();
|
||||
boolean md5sess = algorithm.equalsIgnoreCase ("MD5-sess");
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance(md5sess?"MD5":algorithm);
|
||||
|
||||
if (md5sess) {
|
||||
if ((HashA1 = params.getCachedHA1 ()) == null) {
|
||||
String s = userName + ":" + realm + ":";
|
||||
String s1 = encode (s, password, md);
|
||||
A1 = s1 + ":" + nonceString + ":" + cnonce;
|
||||
HashA1 = encode(A1, null, md);
|
||||
params.setCachedHA1 (HashA1);
|
||||
}
|
||||
} else {
|
||||
A1 = userName + ":" + realm + ":";
|
||||
HashA1 = encode(A1, password, md);
|
||||
}
|
||||
|
||||
String A2;
|
||||
if (isRequest) {
|
||||
A2 = connMethod + ":" + requestURI;
|
||||
} else {
|
||||
A2 = ":" + requestURI;
|
||||
}
|
||||
String HashA2 = encode(A2, null, md);
|
||||
String combo, finalHash;
|
||||
|
||||
if (params.authQop()) { /* RRC2617 when qop=auth */
|
||||
combo = HashA1+ ":" + nonceString + ":" + ncValue + ":" +
|
||||
cnonce + ":auth:" +HashA2;
|
||||
|
||||
} else { /* for compatibility with RFC2069 */
|
||||
combo = HashA1 + ":" +
|
||||
nonceString + ":" +
|
||||
HashA2;
|
||||
}
|
||||
finalHash = encode(combo, null, md);
|
||||
return finalHash;
|
||||
}
|
||||
|
||||
private final static char charArray[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
};
|
||||
|
||||
private final static String zeroPad[] = {
|
||||
// 0 1 2 3 4 5 6 7
|
||||
"00000000", "0000000", "000000", "00000", "0000", "000", "00", "0"
|
||||
};
|
||||
|
||||
private String encode(String src, char[] passwd, MessageDigest md) {
|
||||
try {
|
||||
md.update(src.getBytes("ISO-8859-1"));
|
||||
} catch (java.io.UnsupportedEncodingException uee) {
|
||||
assert false;
|
||||
}
|
||||
if (passwd != null) {
|
||||
byte[] passwdBytes = new byte[passwd.length];
|
||||
for (int i=0; i<passwd.length; i++)
|
||||
passwdBytes[i] = (byte)passwd[i];
|
||||
md.update(passwdBytes);
|
||||
Arrays.fill(passwdBytes, (byte)0x00);
|
||||
}
|
||||
byte[] digest = md.digest();
|
||||
|
||||
StringBuffer res = new StringBuffer(digest.length * 2);
|
||||
for (int i = 0; i < digest.length; i++) {
|
||||
int hashchar = ((digest[i] >>> 4) & 0xf);
|
||||
res.append(charArray[hashchar]);
|
||||
hashchar = (digest[i] & 0xf);
|
||||
res.append(charArray[hashchar]);
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
}
|
||||
64
jdkSrc/jdk8/sun/net/www/protocol/http/Handler.java
Normal file
64
jdkSrc/jdk8/sun/net/www/protocol/http/Handler.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2003, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* HTTP stream opener
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.Proxy;
|
||||
|
||||
/** open an http input stream given a URL */
|
||||
public class Handler extends java.net.URLStreamHandler {
|
||||
protected String proxy;
|
||||
protected int proxyPort;
|
||||
|
||||
protected int getDefaultPort() {
|
||||
return 80;
|
||||
}
|
||||
|
||||
public Handler () {
|
||||
proxy = null;
|
||||
proxyPort = -1;
|
||||
}
|
||||
|
||||
public Handler (String proxy, int port) {
|
||||
this.proxy = proxy;
|
||||
this.proxyPort = port;
|
||||
}
|
||||
|
||||
protected java.net.URLConnection openConnection(URL u)
|
||||
throws IOException {
|
||||
return openConnection(u, (Proxy)null);
|
||||
}
|
||||
|
||||
protected java.net.URLConnection openConnection(URL u, Proxy p)
|
||||
throws IOException {
|
||||
return new HttpURLConnection(u, p, this);
|
||||
}
|
||||
}
|
||||
76
jdkSrc/jdk8/sun/net/www/protocol/http/HttpAuthenticator.java
Normal file
76
jdkSrc/jdk8/sun/net/www/protocol/http/HttpAuthenticator.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2004, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* An interface for all objects that implement HTTP authentication.
|
||||
* See the HTTP spec for details on how this works in general.
|
||||
* A single class or object can implement an arbitrary number of
|
||||
* authentication schemes.
|
||||
*
|
||||
* @author David Brown
|
||||
*
|
||||
* @deprecated -- use java.net.Authenticator instead
|
||||
* @see java.net.Authenticator
|
||||
*/
|
||||
//
|
||||
// REMIND: Unless compatibility with sun.* API's from 1.2 to 2.0 is
|
||||
// a goal, there's no reason to carry this forward into JDK 2.0.
|
||||
@Deprecated
|
||||
public interface HttpAuthenticator {
|
||||
|
||||
|
||||
/**
|
||||
* Indicate whether the specified authentication scheme is
|
||||
* supported. In accordance with HTTP specifications, the
|
||||
* scheme name should be checked in a case-insensitive fashion.
|
||||
*/
|
||||
|
||||
boolean schemeSupported (String scheme);
|
||||
|
||||
/**
|
||||
* Returns the String that should be included in the HTTP
|
||||
* <B>Authorization</B> field. Return null if no info was
|
||||
* supplied or could be found.
|
||||
* <P>
|
||||
* Example:
|
||||
* --> GET http://www.authorization-required.com/ HTTP/1.0
|
||||
* <-- HTTP/1.0 403 Unauthorized
|
||||
* <-- WWW-Authenticate: Basic realm="WallyWorld"
|
||||
* call schemeSupported("Basic"); (return true)
|
||||
* call authString(u, "Basic", "WallyWorld", null);
|
||||
* return "QWadhgWERghghWERfdfQ=="
|
||||
* --> GET http://www.authorization-required.com/ HTTP/1.0
|
||||
* --> Authorization: Basic QWadhgWERghghWERfdfQ==
|
||||
* <-- HTTP/1.0 200 OK
|
||||
* <B> YAY!!!</B>
|
||||
*/
|
||||
|
||||
public String authString (URL u, String scheme, String realm);
|
||||
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/net/www/protocol/http/HttpCallerInfo.java
Normal file
108
jdkSrc/jdk8/sun/net/www/protocol/http/HttpCallerInfo.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.net.Authenticator.RequestorType;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Used in HTTP/Negotiate, to feed HTTP request info into JGSS as a HttpCaller,
|
||||
* so that special actions can be taken, including special callback handler,
|
||||
* special useSubjectCredsOnly value.
|
||||
*
|
||||
* This is an immutable class. It can be instantiated in two styles;
|
||||
*
|
||||
* 1. Un-schemed: Create at the beginning before the preferred scheme is
|
||||
* determined. This object can be fed into AuthenticationHeader to check
|
||||
* for the preference.
|
||||
*
|
||||
* 2. Schemed: With the scheme field filled, can be used in JGSS-API calls.
|
||||
*/
|
||||
final public class HttpCallerInfo {
|
||||
// All info that an Authenticator needs.
|
||||
final public URL url;
|
||||
final public String host, protocol, prompt, scheme;
|
||||
final public int port;
|
||||
final public InetAddress addr;
|
||||
final public RequestorType authType;
|
||||
|
||||
/**
|
||||
* Create a schemed object based on an un-schemed one.
|
||||
*/
|
||||
public HttpCallerInfo(HttpCallerInfo old, String scheme) {
|
||||
this.url = old.url;
|
||||
this.host = old.host;
|
||||
this.protocol = old.protocol;
|
||||
this.prompt = old.prompt;
|
||||
this.port = old.port;
|
||||
this.addr = old.addr;
|
||||
this.authType = old.authType;
|
||||
this.scheme = scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor an un-schemed object for site access.
|
||||
*/
|
||||
public HttpCallerInfo(URL url) {
|
||||
this.url= url;
|
||||
prompt = "";
|
||||
host = url.getHost();
|
||||
|
||||
int p = url.getPort();
|
||||
if (p == -1) {
|
||||
port = url.getDefaultPort();
|
||||
} else {
|
||||
port = p;
|
||||
}
|
||||
|
||||
InetAddress ia;
|
||||
try {
|
||||
ia = InetAddress.getByName(url.getHost());
|
||||
} catch (Exception e) {
|
||||
ia = null;
|
||||
}
|
||||
addr = ia;
|
||||
|
||||
protocol = url.getProtocol();
|
||||
authType = RequestorType.SERVER;
|
||||
scheme = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor an un-schemed object for proxy access.
|
||||
*/
|
||||
public HttpCallerInfo(URL url, String host, int port) {
|
||||
this.url= url;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
prompt = "";
|
||||
addr = null;
|
||||
protocol = url.getProtocol();
|
||||
authType = RequestorType.PROXY;
|
||||
scheme = "";
|
||||
}
|
||||
}
|
||||
3834
jdkSrc/jdk8/sun/net/www/protocol/http/HttpURLConnection.java
Normal file
3834
jdkSrc/jdk8/sun/net/www/protocol/http/HttpURLConnection.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
/**
|
||||
* Proxy class for loading NTLMAuthentication, so as to remove static
|
||||
* dependancy.
|
||||
*/
|
||||
class NTLMAuthenticationProxy {
|
||||
private static Method supportsTA;
|
||||
private static Method isTrustedSite;
|
||||
private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication";
|
||||
private static final String supportsTAStr = "supportsTransparentAuth";
|
||||
private static final String isTrustedSiteStr = "isTrustedSite";
|
||||
|
||||
static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
|
||||
static final boolean supported = proxy != null ? true : false;
|
||||
static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
|
||||
|
||||
private final Constructor<? extends AuthenticationInfo> threeArgCtr;
|
||||
private final Constructor<? extends AuthenticationInfo> fiveArgCtr;
|
||||
|
||||
private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
|
||||
Constructor<? extends AuthenticationInfo> fiveArgCtr) {
|
||||
this.threeArgCtr = threeArgCtr;
|
||||
this.fiveArgCtr = fiveArgCtr;
|
||||
}
|
||||
|
||||
|
||||
AuthenticationInfo create(boolean isProxy,
|
||||
URL url,
|
||||
PasswordAuthentication pw) {
|
||||
try {
|
||||
return threeArgCtr.newInstance(isProxy, url, pw);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
finest(roe);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
AuthenticationInfo create(boolean isProxy,
|
||||
String host,
|
||||
int port,
|
||||
PasswordAuthentication pw) {
|
||||
try {
|
||||
return fiveArgCtr.newInstance(isProxy, host, port, pw);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
finest(roe);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Returns true if the NTLM implementation supports transparent
|
||||
* authentication (try with the current users credentials before
|
||||
* prompting for username and password, etc).
|
||||
*/
|
||||
private static boolean supportsTransparentAuth() {
|
||||
try {
|
||||
return (Boolean)supportsTA.invoke(null);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
finest(roe);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Transparent authentication should only be tried with a trusted
|
||||
* site ( when running in a secure environment ).
|
||||
*/
|
||||
public static boolean isTrustedSite(URL url) {
|
||||
try {
|
||||
return (Boolean)isTrustedSite.invoke(null, url);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
finest(roe);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the NTLM authentiation implementation through reflection. If
|
||||
* the class is present, then it must have the required constructors and
|
||||
* method. Otherwise, it is considered an error.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
|
||||
Class<? extends AuthenticationInfo> cl;
|
||||
Constructor<? extends AuthenticationInfo> threeArg, fiveArg;
|
||||
try {
|
||||
cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
|
||||
if (cl != null) {
|
||||
threeArg = cl.getConstructor(boolean.class,
|
||||
URL.class,
|
||||
PasswordAuthentication.class);
|
||||
fiveArg = cl.getConstructor(boolean.class,
|
||||
String.class,
|
||||
int.class,
|
||||
PasswordAuthentication.class);
|
||||
supportsTA = cl.getDeclaredMethod(supportsTAStr);
|
||||
isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
|
||||
return new NTLMAuthenticationProxy(threeArg,
|
||||
fiveArg);
|
||||
}
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
finest(cnfe);
|
||||
} catch (ReflectiveOperationException roe) {
|
||||
throw new AssertionError(roe);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static void finest(Exception e) {
|
||||
PlatformLogger logger = HttpURLConnection.getHttpLogger();
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
logger.finest("NTLMAuthenticationProxy: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator.RequestorType;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import sun.net.www.HeaderParser;
|
||||
import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
|
||||
import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* NegotiateAuthentication:
|
||||
*
|
||||
* @author weijun.wang@sun.com
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
class NegotiateAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
final private HttpCallerInfo hci;
|
||||
|
||||
// These maps are used to manage the GSS availability for diffrent
|
||||
// hosts. The key for both maps is the host name.
|
||||
// <code>supported</code> is set when isSupported is checked,
|
||||
|
||||
// if it's true, a cached Negotiator is put into <code>cache</code>.
|
||||
// the cache can be used only once, so after the first use, it's cleaned.
|
||||
static HashMap <String, Boolean> supported = null;
|
||||
static ThreadLocal <HashMap <String, Negotiator>> cache = null;
|
||||
/* Whether cache is enabled for Negotiate/Kerberos */
|
||||
private static final boolean cacheSPNEGO;
|
||||
static {
|
||||
String spnegoCacheProp = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("jdk.spnego.cache", "true"));
|
||||
cacheSPNEGO = Boolean.parseBoolean(spnegoCacheProp);
|
||||
}
|
||||
|
||||
// The HTTP Negotiate Helper
|
||||
private Negotiator negotiator = null;
|
||||
|
||||
/**
|
||||
* Constructor used for both WWW and proxy entries.
|
||||
* @param hci a schemed object.
|
||||
*/
|
||||
public NegotiateAuthentication(HttpCallerInfo hci) {
|
||||
super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
|
||||
hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
|
||||
hci.url,
|
||||
"");
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if the HttpCallerInfo supports Negotiate protocol. In order to
|
||||
* find out yes or no, an initialization of a Negotiator object against it
|
||||
* is tried. The generated object will be cached under the name of ths
|
||||
* hostname at a success try.<br>
|
||||
*
|
||||
* If this method is called for the second time on an HttpCallerInfo with
|
||||
* the same hostname, the answer is retrieved from cache.
|
||||
*
|
||||
* @return true if supported
|
||||
*/
|
||||
synchronized public static boolean isSupported(HttpCallerInfo hci) {
|
||||
if (supported == null) {
|
||||
supported = new HashMap<>();
|
||||
}
|
||||
String hostname = hci.host;
|
||||
hostname = hostname.toLowerCase();
|
||||
if (supported.containsKey(hostname)) {
|
||||
return supported.get(hostname);
|
||||
}
|
||||
|
||||
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
|
||||
if (cache == null) {
|
||||
cache = new ThreadLocal<HashMap<String, Negotiator>>() {
|
||||
@Override
|
||||
protected HashMap<String, Negotiator> initialValue() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
};
|
||||
}
|
||||
cache.get().put(hostname, neg);
|
||||
return true;
|
||||
} else {
|
||||
supported.put(hostname, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized HashMap<String, Negotiator> getCache() {
|
||||
if (cache == null) return null;
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useAuthCache() {
|
||||
return super.useAuthCache() && cacheSPNEGO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Negotiate */
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
byte[] incoming = null;
|
||||
String[] parts = raw.split("\\s+");
|
||||
if (parts.length > 1) {
|
||||
incoming = Base64.getDecoder().decode(parts[1]);
|
||||
}
|
||||
response = hci.scheme + " " + Base64.getEncoder().encodeToString(
|
||||
incoming==null?firstToken():nextToken(incoming));
|
||||
|
||||
conn.setAuthenticationProperty(getHeaderName(), response);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* return the first token.
|
||||
* @returns the token
|
||||
* @throws IOException if <code>Negotiator.getNegotiator()</code> or
|
||||
* <code>Negotiator.firstToken()</code> failed.
|
||||
*/
|
||||
private byte[] firstToken() throws IOException {
|
||||
negotiator = null;
|
||||
HashMap <String, Negotiator> cachedMap = getCache();
|
||||
if (cachedMap != null) {
|
||||
negotiator = cachedMap.get(getHost());
|
||||
if (negotiator != null) {
|
||||
cachedMap.remove(getHost()); // so that it is only used once
|
||||
}
|
||||
}
|
||||
if (negotiator == null) {
|
||||
negotiator = Negotiator.getNegotiator(hci);
|
||||
if (negotiator == null) {
|
||||
IOException ioe = new IOException("Cannot initialize Negotiator");
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
return negotiator.firstToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* return more tokens
|
||||
* @param token the token to be fed into <code>negotiator.nextToken()</code>
|
||||
* @returns the token
|
||||
* @throws IOException if <code>negotiator.nextToken()</code> throws Exception.
|
||||
* May happen if the input token is invalid.
|
||||
*/
|
||||
private byte[] nextToken(byte[] token) throws IOException {
|
||||
return negotiator.nextToken(token);
|
||||
}
|
||||
|
||||
// MS will send a final WWW-Authenticate even if the status is already
|
||||
// 200 OK. The token can be fed into initSecContext() again to determine
|
||||
// if the server can be trusted. This is not the same concept as Digest's
|
||||
// Authentication-Info header.
|
||||
//
|
||||
// Currently we ignore this header.
|
||||
|
||||
}
|
||||
84
jdkSrc/jdk8/sun/net/www/protocol/http/Negotiator.java
Normal file
84
jdkSrc/jdk8/sun/net/www/protocol/http/Negotiator.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.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();
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINEST)) {
|
||||
logger.finest("NegotiateAuthentication: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2009, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.logging;
|
||||
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.regex.*;
|
||||
|
||||
/**
|
||||
* A Formatter to make the HTTP logs a bit more palatable to the developer
|
||||
* looking at them. The idea is to present the HTTP events in such a way that
|
||||
* commands and headers are easily spotted (i.e. on separate lines).
|
||||
* @author jccollet
|
||||
*/
|
||||
public class HttpLogFormatter extends java.util.logging.SimpleFormatter {
|
||||
// Pattern for MessageHeader data. Mostly pairs within curly brackets
|
||||
private static volatile Pattern pattern = null;
|
||||
// Pattern for Cookies
|
||||
private static volatile Pattern cpattern = null;
|
||||
|
||||
public HttpLogFormatter() {
|
||||
if (pattern == null) {
|
||||
pattern = Pattern.compile("\\{[^\\}]*\\}");
|
||||
cpattern = Pattern.compile("[^,\\] ]{2,}");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String sourceClassName = record.getSourceClassName();
|
||||
if (sourceClassName == null ||
|
||||
!(sourceClassName.startsWith("sun.net.www.protocol.http") ||
|
||||
sourceClassName.startsWith("sun.net.www.http"))) {
|
||||
return super.format(record);
|
||||
}
|
||||
String src = record.getMessage();
|
||||
StringBuilder buf = new StringBuilder("HTTP: ");
|
||||
if (src.startsWith("sun.net.www.MessageHeader@")) {
|
||||
// MessageHeader logs are composed of pairs within curly brackets
|
||||
// Let's extract them to make it more readable. That way we get one
|
||||
// header pair (name, value) per line. A lot easier to read.
|
||||
Matcher match = pattern.matcher(src);
|
||||
while (match.find()) {
|
||||
int i = match.start();
|
||||
int j = match.end();
|
||||
String s = src.substring(i + 1, j - 1);
|
||||
if (s.startsWith("null: ")) {
|
||||
s = s.substring(6);
|
||||
}
|
||||
if (s.endsWith(": null")) {
|
||||
s = s.substring(0, s.length() - 6);
|
||||
}
|
||||
buf.append("\t").append(s).append("\n");
|
||||
}
|
||||
} else if (src.startsWith("Cookies retrieved: {")) {
|
||||
// This comes from the Cookie handler, let's clean up the format a bit
|
||||
String s = src.substring(20);
|
||||
buf.append("Cookies from handler:\n");
|
||||
while (s.length() >= 7) {
|
||||
if (s.startsWith("Cookie=[")) {
|
||||
String s2 = s.substring(8);
|
||||
int c = s2.indexOf("Cookie2=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
if (s2.length() < 4) {
|
||||
continue;
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i + 1, j > 0 ? j - 1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.startsWith("Cookie2=[")) {
|
||||
String s2 = s.substring(9);
|
||||
int c = s2.indexOf("Cookie=[");
|
||||
if (c > 0) {
|
||||
s2 = s2.substring(0, c-1);
|
||||
s = s2.substring(c);
|
||||
} else {
|
||||
s = "";
|
||||
}
|
||||
Matcher m = cpattern.matcher(s2);
|
||||
while (m.find()) {
|
||||
int i = m.start();
|
||||
int j = m.end();
|
||||
if (i >= 0) {
|
||||
String cookie = s2.substring(i+1, j > 0 ? j-1 : s2.length() - 1);
|
||||
buf.append("\t").append(cookie).append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Anything else we let as is.
|
||||
buf.append(src).append("\n");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.ntlm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
/*
|
||||
* Hooks into Windows implementation of NTLM.
|
||||
* This class will be replaced if a cross-platform version of NTLM
|
||||
* is implemented in the future.
|
||||
*/
|
||||
|
||||
public class NTLMAuthSequence {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
private String ntdomain;
|
||||
private int state;
|
||||
private long crdHandle;
|
||||
private long ctxHandle;
|
||||
|
||||
static {
|
||||
initFirst(Status.class);
|
||||
}
|
||||
|
||||
// Used by native code to indicate when a particular protocol sequence is completed
|
||||
// and must not be re-used.
|
||||
|
||||
class Status {
|
||||
boolean sequenceComplete;
|
||||
}
|
||||
|
||||
Status status;
|
||||
|
||||
NTLMAuthSequence (String username, String password, String ntdomain)
|
||||
throws IOException
|
||||
{
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.ntdomain = ntdomain;
|
||||
this.status = new Status();
|
||||
state = 0;
|
||||
crdHandle = getCredentialsHandle (username, ntdomain, password);
|
||||
if (crdHandle == 0) {
|
||||
throw new IOException ("could not get credentials handle");
|
||||
}
|
||||
}
|
||||
|
||||
public String getAuthHeader (String token) throws IOException {
|
||||
byte[] input = null;
|
||||
|
||||
assert !status.sequenceComplete;
|
||||
|
||||
if (token != null)
|
||||
input = Base64.getDecoder().decode(token);
|
||||
byte[] b = getNextToken (crdHandle, input, status);
|
||||
if (b == null)
|
||||
throw new IOException ("Internal authentication error");
|
||||
return Base64.getEncoder().encodeToString(b);
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return status.sequenceComplete;
|
||||
}
|
||||
|
||||
private native static void initFirst (Class<NTLMAuthSequence.Status> clazz);
|
||||
|
||||
private native long getCredentialsHandle (String user, String domain, String password);
|
||||
|
||||
private native byte[] getNextToken (long crdHandle, byte[] lastToken, Status returned);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.ntlm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.URL;
|
||||
import sun.net.NetProperties;
|
||||
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
|
||||
*/
|
||||
|
||||
public class NTLMAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
private static final NTLMAuthenticationCallback NTLMAuthCallback =
|
||||
NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
|
||||
|
||||
private String hostname;
|
||||
private static String defaultDomain; /* Domain to use if not specified by user */
|
||||
private static final boolean ntlmCache; /* Whether cache is enabled for NTLM */
|
||||
|
||||
enum TransparentAuth {
|
||||
DISABLED, // disable for all hosts (default)
|
||||
TRUSTED_HOSTS, // use Windows trusted hosts settings
|
||||
ALL_HOSTS // attempt for all hosts
|
||||
}
|
||||
|
||||
private static final TransparentAuth authMode;
|
||||
|
||||
static {
|
||||
defaultDomain = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
|
||||
"domain"));
|
||||
String ntlmCacheProp = java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetPropertyAction("jdk.ntlm.cache", "true"));
|
||||
ntlmCache = Boolean.parseBoolean(ntlmCacheProp);
|
||||
String modeProp = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return NetProperties.get("jdk.http.ntlm.transparentAuth");
|
||||
}
|
||||
});
|
||||
|
||||
if ("trustedHosts".equalsIgnoreCase(modeProp))
|
||||
authMode = TransparentAuth.TRUSTED_HOSTS;
|
||||
else if ("allHosts".equalsIgnoreCase(modeProp))
|
||||
authMode = TransparentAuth.ALL_HOSTS;
|
||||
else
|
||||
authMode = TransparentAuth.DISABLED;
|
||||
};
|
||||
|
||||
private void init0() {
|
||||
|
||||
hostname = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
String username;
|
||||
String ntdomain;
|
||||
String password;
|
||||
|
||||
/**
|
||||
* Create a NTLMAuthentication:
|
||||
* Username may be specified as domain<BACKSLASH>username 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;
|
||||
if (pw != null) {
|
||||
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());
|
||||
} else {
|
||||
/* credentials will be acquired from OS */
|
||||
username = null;
|
||||
ntdomain = null;
|
||||
password = null;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useAuthCache() {
|
||||
return ntlmCache && super.useAuthCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this authentication supports preemptive authorization
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsPreemptiveAuthorization() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if NTLM supported transparently (no password needed, SSO)
|
||||
*/
|
||||
public static boolean supportsTransparentAuth() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given site is trusted, i.e. we can try
|
||||
* transparent Authentication.
|
||||
*/
|
||||
public static boolean isTrustedSite(URL url) {
|
||||
if (NTLMAuthCallback != null)
|
||||
return NTLMAuthCallback.isTrustedSite(url);
|
||||
|
||||
switch (authMode) {
|
||||
case TRUSTED_HOSTS:
|
||||
return isTrustedSite(url.toString());
|
||||
case ALL_HOSTS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean isTrustedSiteAvailable = isTrustedSiteAvailable();
|
||||
|
||||
private static native boolean isTrustedSiteAvailable();
|
||||
|
||||
private static boolean isTrustedSite(String url) {
|
||||
if (isTrustedSiteAvailable)
|
||||
return isTrustedSite0(url);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static native boolean isTrustedSite0(String url);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj();
|
||||
if (seq == null) {
|
||||
seq = new NTLMAuthSequence (username, password, ntdomain);
|
||||
conn.authObj(seq);
|
||||
}
|
||||
String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
|
||||
conn.setAuthenticationProperty(getHeaderName(), response);
|
||||
if (seq.isComplete()) {
|
||||
conn.authObj(null);
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
conn.authObj(null);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.ntlm;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* This class is used to call back to deployment to determine if a given
|
||||
* URL is trusted. Transparent authentication (try with logged in users
|
||||
* credentials without prompting) should only be tried with trusted sites.
|
||||
*/
|
||||
public abstract class NTLMAuthenticationCallback {
|
||||
private static volatile NTLMAuthenticationCallback callback;
|
||||
|
||||
public static void setNTLMAuthenticationCallback(
|
||||
NTLMAuthenticationCallback callback) {
|
||||
NTLMAuthenticationCallback.callback = callback;
|
||||
}
|
||||
|
||||
public static NTLMAuthenticationCallback getNTLMAuthenticationCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given site is trusted, i.e. we can try
|
||||
* transparent Authentication.
|
||||
*/
|
||||
public abstract boolean isTrustedSite(URL url);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.spnego;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.util.Arrays;
|
||||
import javax.security.auth.callback.Callback;
|
||||
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;
|
||||
import sun.security.jgss.LoginConfigImpl;
|
||||
|
||||
/**
|
||||
* @since 1.6
|
||||
* Special callback handler used in JGSS for the HttpCaller.
|
||||
*/
|
||||
public class NegotiateCallbackHandler implements CallbackHandler {
|
||||
|
||||
private String username;
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Authenticator asks for username and password in a single prompt,
|
||||
* but CallbackHandler checks one by one. So, no matter which callback
|
||||
* gets handled first, make sure Authenticator is only called once.
|
||||
*/
|
||||
private boolean answered;
|
||||
|
||||
private final HttpCallerInfo hci;
|
||||
|
||||
public NegotiateCallbackHandler(HttpCallerInfo hci) {
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
private void getAnswer() {
|
||||
if (!answered) {
|
||||
answered = true;
|
||||
|
||||
if (LoginConfigImpl.HTTP_USE_GLOBAL_CREDS) {
|
||||
PasswordAuthentication passAuth =
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
hci.host, hci.addr, hci.port, hci.protocol,
|
||||
hci.prompt, hci.scheme, hci.url, hci.authType);
|
||||
/**
|
||||
* To be compatible with existing callback handler implementations,
|
||||
* when the underlying Authenticator is canceled, username and
|
||||
* password are assigned null. No exception is thrown.
|
||||
*/
|
||||
if (passAuth != null) {
|
||||
username = passAuth.getUserName();
|
||||
password = passAuth.getPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks) throws
|
||||
UnsupportedCallbackException, IOException {
|
||||
for (int i=0; i<callbacks.length; i++) {
|
||||
Callback callBack = callbacks[i];
|
||||
|
||||
if (callBack instanceof NameCallback) {
|
||||
getAnswer();
|
||||
((NameCallback)callBack).setName(username);
|
||||
} else if (callBack instanceof PasswordCallback) {
|
||||
getAnswer();
|
||||
((PasswordCallback)callBack).setPassword(password);
|
||||
if (password != null) Arrays.fill(password, ' ');
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callBack,
|
||||
"Call back not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
159
jdkSrc/jdk8/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
Normal file
159
jdkSrc/jdk8/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.www.protocol.http.spnego;
|
||||
|
||||
import com.sun.security.jgss.ExtendedGSSContext;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.ietf.jgss.GSSContext;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This class encapsulates all JAAS and JGSS API calls in a separate class
|
||||
* outside NegotiateAuthentication.java so that J2SE build can go smoothly
|
||||
* without the presence of it.
|
||||
*
|
||||
* @author weijun.wang@sun.com
|
||||
* @since 1.6
|
||||
*/
|
||||
public class NegotiatorImpl extends Negotiator {
|
||||
|
||||
private static final boolean DEBUG =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
|
||||
|
||||
private GSSContext context;
|
||||
private byte[] oneToken;
|
||||
|
||||
/**
|
||||
* Initialize the object, which includes:<ul>
|
||||
* <li>Find out what GSS mechanism to use from the system property
|
||||
* <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO
|
||||
* <li>Creating the GSSName for the target host, "HTTP/"+hostname
|
||||
* <li>Creating GSSContext
|
||||
* <li>A first call to initSecContext</ul>
|
||||
*/
|
||||
private void init(HttpCallerInfo hci) throws GSSException {
|
||||
final Oid oid;
|
||||
|
||||
if (hci.scheme.equalsIgnoreCase("Kerberos")) {
|
||||
// we can only use Kerberos mech when the scheme is kerberos
|
||||
oid = GSSUtil.GSS_KRB5_MECH_OID;
|
||||
} else {
|
||||
String pref = java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<String>() {
|
||||
public String run() {
|
||||
return System.getProperty(
|
||||
"http.auth.preference",
|
||||
"spnego");
|
||||
}
|
||||
});
|
||||
if (pref.equalsIgnoreCase("kerberos")) {
|
||||
oid = GSSUtil.GSS_KRB5_MECH_OID;
|
||||
} else {
|
||||
// currently there is no 3rd mech we can use
|
||||
oid = GSSUtil.GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
}
|
||||
|
||||
GSSManagerImpl manager = new GSSManagerImpl(
|
||||
new HttpCaller(hci));
|
||||
|
||||
// RFC 4559 4.1 uses uppercase service name "HTTP".
|
||||
// RFC 4120 6.2.1 demands the host be lowercase
|
||||
String peerName = "HTTP@" + hci.host.toLowerCase();
|
||||
|
||||
GSSName serverName = manager.createName(peerName,
|
||||
GSSName.NT_HOSTBASED_SERVICE);
|
||||
context = manager.createContext(serverName,
|
||||
oid,
|
||||
null,
|
||||
GSSContext.DEFAULT_LIFETIME);
|
||||
|
||||
// Always respect delegation policy in HTTP/SPNEGO.
|
||||
if (context instanceof ExtendedGSSContext) {
|
||||
((ExtendedGSSContext)context).requestDelegPolicy(true);
|
||||
}
|
||||
oneToken = context.initSecContext(new byte[0], 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @throws java.io.IOException If negotiator cannot be constructed
|
||||
*/
|
||||
public NegotiatorImpl(HttpCallerInfo hci) throws IOException {
|
||||
try {
|
||||
init(hci);
|
||||
} catch (GSSException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Negotiate support not initiated, will " +
|
||||
"fallback to other scheme if allowed. Reason:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
IOException ioe = new IOException("Negotiate support not initiated");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first token of GSS, in SPNEGO, it's called NegTokenInit
|
||||
* @return the first token
|
||||
*/
|
||||
@Override
|
||||
public byte[] firstToken() {
|
||||
return oneToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg
|
||||
* @param token the token received from server
|
||||
* @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);
|
||||
} catch (GSSException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Negotiate support cannot continue. Reason:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
IOException ioe = new IOException("Negotiate support cannot continue");
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user