src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 



  28 import java.util.HashMap;
  29 
  30 import sun.net.www.HeaderParser;
  31 import sun.misc.BASE64Decoder;
  32 import sun.misc.BASE64Encoder;
  33 import sun.util.logging.PlatformLogger;
  34 
  35 import java.net.URL;
  36 import java.io.IOException;
  37 import java.net.Authenticator.RequestorType;
  38 import java.lang.reflect.Constructor;
  39 import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
  40 import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
  41 
  42 /**
  43  * NegotiateAuthentication:
  44  *
  45  * @author weijun.wang@sun.com
  46  * @since 1.6
  47  */
  48 
  49 class NegotiateAuthentication extends AuthenticationInfo {
  50 
  51     private static final long serialVersionUID = 100L;
  52 
  53     final private HttpCallerInfo hci;
  54 
  55     // These maps are used to manage the GSS availability for diffrent
  56     // hosts. The key for both maps is the host name.
  57     // <code>supported</code> is set when isSupported is checked,
  58     // if it's true, a cached Negotiator is put into <code>cache</code>.


  61     static HashMap <String, Negotiator> cache = null;
  62 
  63     // The HTTP Negotiate Helper
  64     private Negotiator negotiator = null;
  65 
  66    /**
  67     * Constructor used for both WWW and proxy entries.
  68     * @param hci a schemed object.
  69     */
  70     public NegotiateAuthentication(HttpCallerInfo hci) {
  71         super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
  72               hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
  73               hci.url,
  74               "");
  75         this.hci = hci;
  76     }
  77 
  78     /**
  79      * @return true if this authentication supports preemptive authorization
  80      */
  81     boolean supportsPreemptiveAuthorization() {

  82         return false;
  83     }
  84 
  85     /**
  86      * Find out if the HttpCallerInfo supports Negotiate protocol. In order to
  87      * find out yes or no, an initialization of a Negotiator object against it
  88      * is tried. The generated object will be cached under the name of ths
  89      * hostname at a success try.<br>
  90      *
  91      * If this method is called for the second time on an HttpCallerInfo with
  92      * the same hostname, the answer is retrieved from cache.
  93      *
  94      * @return true if supported
  95      */
  96     synchronized public static boolean isSupported(HttpCallerInfo hci) {
  97         if (supported == null) {
  98             supported = new HashMap <String, Boolean>();
  99             cache = new HashMap <String, Negotiator>();
 100         }
 101         String hostname = hci.host;
 102         hostname = hostname.toLowerCase();
 103         if (supported.containsKey(hostname)) {
 104             return supported.get(hostname);
 105         }
 106 
 107         try {
 108             Negotiator neg = Negotiator.getSupported(hci);
 109             supported.put(hostname, true);
 110             // the only place cache.put is called. here we can make sure
 111             // the object is valid and the oneToken inside is not null
 112             cache.put(hostname, neg);
 113             return true;
 114         } catch(Exception e) {
 115             supported.put(hostname, false);
 116             return false;
 117         }
 118     }
 119 
 120     /**
 121      * @return the name of the HTTP header this authentication wants to set
 122      */
 123     String getHeaderName() {
 124         if (type == SERVER_AUTHENTICATION) {
 125             return "Authorization";
 126         } else {
 127             return "Proxy-Authorization";
 128         }
 129     }
 130 
 131     /**
 132      * Not supported. Must use the setHeaders() method
 133      */
 134     String getHeaderValue(URL url, String method) {

 135         throw new RuntimeException ("getHeaderValue not supported");
 136     }
 137 
 138     /**
 139      * Check if the header indicates that the current auth. parameters are stale.
 140      * If so, then replace the relevant field with the new value
 141      * and return true. Otherwise return false.
 142      * returning true means the request can be retried with the same userid/password
 143      * returning false means we have to go back to the user to ask for a new
 144      * username password.
 145      */
 146     boolean isAuthorizationStale (String header) {

 147         return false; /* should not be called for Negotiate */
 148     }
 149 
 150     /**
 151      * Set header(s) on the given connection.
 152      * @param conn The connection to apply the header(s) to
 153      * @param p A source of header values for this connection, not used because
 154      *          HeaderParser converts the fields to lower case, use raw instead
 155      * @param raw The raw header field.
 156      * @return true if all goes well, false if no headers were set.
 157      */
 158     synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {

 159 
 160         try {
 161             String response;
 162             byte[] incoming = null;
 163             String[] parts = raw.split("\\s+");
 164             if (parts.length > 1) {
 165                 incoming = new BASE64Decoder().decodeBuffer(parts[1]);
 166             }
 167             response = hci.scheme + " " + new B64Encoder().encode(
 168                         incoming==null?firstToken():nextToken(incoming));
 169 
 170             conn.setAuthenticationProperty(getHeaderName(), response);
 171             return true;
 172         } catch (IOException e) {
 173             return false;
 174         }
 175     }
 176 
 177     /**
 178      * return the first token.


 210      * @throws IOException if <code>negotiator.nextToken()</code> throws Exception.
 211      *  May happen if the input token is invalid.
 212      */
 213     private byte[] nextToken(byte[] token) throws IOException {
 214         return negotiator.nextToken(token);
 215     }
 216 
 217     class B64Encoder extends BASE64Encoder {
 218         protected int bytesPerLine () {
 219             return 100000;  // as big as it can be, maybe INT_MAX
 220         }
 221     }
 222 
 223     // MS will send a final WWW-Authenticate even if the status is already
 224     // 200 OK. The token can be fed into initSecContext() again to determine
 225     // if the server can be trusted. This is not the same concept as Digest's
 226     // Authentication-Info header.
 227     //
 228     // Currently we ignore this header.
 229 
 230 }
 231 
 232 /**
 233  * This abstract class is a bridge to connect NegotiteAuthentication and
 234  * NegotiatorImpl, so that JAAS and JGSS calls can be made
 235  */
 236 abstract class Negotiator {
 237     static Negotiator getSupported(HttpCallerInfo hci)
 238                 throws Exception {
 239 
 240         // These lines are equivalent to
 241         //     return new NegotiatorImpl(hci);
 242         // The current implementation will make sure NegotiatorImpl is not
 243         // directly referenced when compiling, thus smooth the way of building
 244         // the J2SE platform where HttpURLConnection is a bootstrap class.
 245         //
 246         // Makes NegotiatorImpl, and the security classes it references, a
 247         // runtime dependency rather than a static one.
 248 
 249         Class clazz;
 250         Constructor c;
 251         try {
 252             clazz = Class.forName("sun.net.www.protocol.http.NegotiatorImpl", true, null);
 253             c = clazz.getConstructor(HttpCallerInfo.class);
 254         } catch (ClassNotFoundException cnfe) {
 255             finest(cnfe);
 256             throw cnfe;
 257         } catch (ReflectiveOperationException roe) {
 258             // if the class is there then something seriously wrong if
 259             // the constructor is not.
 260             throw new AssertionError(roe);
 261         }
 262 
 263         try {
 264             return (Negotiator) (c.newInstance(hci));
 265         } catch (ReflectiveOperationException roe) {
 266             finest(roe);
 267             Throwable t = roe.getCause();
 268             if (t != null && t instanceof Exception)
 269                 finest((Exception)t);
 270             throw roe;
 271         }
 272     }
 273 
 274     abstract byte[] firstToken() throws IOException;
 275 
 276     abstract byte[] nextToken(byte[] in) throws IOException;
 277 
 278     static void finest(Exception e) {
 279         PlatformLogger logger = HttpURLConnection.getHttpLogger();
 280         logger.finest("NegotiateAuthentication: " + e);
 281     }
 282 }


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.net.www.protocol.http;
  27 
  28 import java.net.URL;
  29 import java.io.IOException;
  30 import java.net.Authenticator.RequestorType;
  31 import java.util.HashMap;

  32 import sun.net.www.HeaderParser;
  33 import sun.misc.BASE64Decoder;
  34 import sun.misc.BASE64Encoder;






  35 import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
  36 import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
  37 
  38 /**
  39  * NegotiateAuthentication:
  40  *
  41  * @author weijun.wang@sun.com
  42  * @since 1.6
  43  */
  44 
  45 class NegotiateAuthentication extends AuthenticationInfo {
  46 
  47     private static final long serialVersionUID = 100L;
  48 
  49     final private HttpCallerInfo hci;
  50 
  51     // These maps are used to manage the GSS availability for diffrent
  52     // hosts. The key for both maps is the host name.
  53     // <code>supported</code> is set when isSupported is checked,
  54     // if it's true, a cached Negotiator is put into <code>cache</code>.


  57     static HashMap <String, Negotiator> cache = null;
  58 
  59     // The HTTP Negotiate Helper
  60     private Negotiator negotiator = null;
  61 
  62    /**
  63     * Constructor used for both WWW and proxy entries.
  64     * @param hci a schemed object.
  65     */
  66     public NegotiateAuthentication(HttpCallerInfo hci) {
  67         super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
  68               hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
  69               hci.url,
  70               "");
  71         this.hci = hci;
  72     }
  73 
  74     /**
  75      * @return true if this authentication supports preemptive authorization
  76      */
  77     @Override
  78     public boolean supportsPreemptiveAuthorization() {
  79         return false;
  80     }
  81 
  82     /**
  83      * Find out if the HttpCallerInfo supports Negotiate protocol. In order to
  84      * find out yes or no, an initialization of a Negotiator object against it
  85      * is tried. The generated object will be cached under the name of ths
  86      * hostname at a success try.<br>
  87      *
  88      * If this method is called for the second time on an HttpCallerInfo with
  89      * the same hostname, the answer is retrieved from cache.
  90      *
  91      * @return true if supported
  92      */
  93     synchronized public static boolean isSupported(HttpCallerInfo hci) {
  94         if (supported == null) {
  95             supported = new HashMap <String, Boolean>();
  96             cache = new HashMap <String, Negotiator>();
  97         }
  98         String hostname = hci.host;
  99         hostname = hostname.toLowerCase();
 100         if (supported.containsKey(hostname)) {
 101             return supported.get(hostname);
 102         }
 103 
 104         try {
 105             Negotiator neg = Negotiator.getSupported(hci);
 106             supported.put(hostname, true);
 107             // the only place cache.put is called. here we can make sure
 108             // the object is valid and the oneToken inside is not null
 109             cache.put(hostname, neg);
 110             return true;
 111         } catch(Exception e) {
 112             supported.put(hostname, false);
 113             return false;
 114         }
 115     }
 116 
 117     /**











 118      * Not supported. Must use the setHeaders() method
 119      */
 120     @Override
 121     public String getHeaderValue(URL url, String method) {
 122         throw new RuntimeException ("getHeaderValue not supported");
 123     }
 124 
 125     /**
 126      * Check if the header indicates that the current auth. parameters are stale.
 127      * If so, then replace the relevant field with the new value
 128      * and return true. Otherwise return false.
 129      * returning true means the request can be retried with the same userid/password
 130      * returning false means we have to go back to the user to ask for a new
 131      * username password.
 132      */
 133     @Override
 134     public boolean isAuthorizationStale (String header) {
 135         return false; /* should not be called for Negotiate */
 136     }
 137 
 138     /**
 139      * Set header(s) on the given connection.
 140      * @param conn The connection to apply the header(s) to
 141      * @param p A source of header values for this connection, not used because
 142      *          HeaderParser converts the fields to lower case, use raw instead
 143      * @param raw The raw header field.
 144      * @return true if all goes well, false if no headers were set.
 145      */
 146     @Override
 147     public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
 148 
 149         try {
 150             String response;
 151             byte[] incoming = null;
 152             String[] parts = raw.split("\\s+");
 153             if (parts.length > 1) {
 154                 incoming = new BASE64Decoder().decodeBuffer(parts[1]);
 155             }
 156             response = hci.scheme + " " + new B64Encoder().encode(
 157                         incoming==null?firstToken():nextToken(incoming));
 158 
 159             conn.setAuthenticationProperty(getHeaderName(), response);
 160             return true;
 161         } catch (IOException e) {
 162             return false;
 163         }
 164     }
 165 
 166     /**
 167      * return the first token.


 199      * @throws IOException if <code>negotiator.nextToken()</code> throws Exception.
 200      *  May happen if the input token is invalid.
 201      */
 202     private byte[] nextToken(byte[] token) throws IOException {
 203         return negotiator.nextToken(token);
 204     }
 205 
 206     class B64Encoder extends BASE64Encoder {
 207         protected int bytesPerLine () {
 208             return 100000;  // as big as it can be, maybe INT_MAX
 209         }
 210     }
 211 
 212     // MS will send a final WWW-Authenticate even if the status is already
 213     // 200 OK. The token can be fed into initSecContext() again to determine
 214     // if the server can be trusted. This is not the same concept as Digest's
 215     // Authentication-Info header.
 216     //
 217     // Currently we ignore this header.
 218 




















































 219 }