1 /*
   2  * Copyright 2005-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   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.spnego;
  27 
  28 import java.io.IOException;
  29 
  30 import org.ietf.jgss.GSSContext;
  31 import org.ietf.jgss.GSSException;
  32 import org.ietf.jgss.GSSName;
  33 import org.ietf.jgss.Oid;
  34 
  35 import sun.net.www.protocol.http.HttpCallerInfo;
  36 import sun.net.www.protocol.http.Negotiator;
  37 import sun.security.jgss.GSSManagerImpl;
  38 import sun.security.jgss.GSSUtil;
  39 import sun.security.jgss.HttpCaller;
  40 
  41 /**
  42  * This class encapsulates all JAAS and JGSS API calls in a separate class
  43  * outside NegotiateAuthentication.java so that J2SE build can go smoothly
  44  * without the presence of it.
  45  *
  46  * @author weijun.wang@sun.com
  47  * @since 1.6
  48  */
  49 public class NegotiatorImpl extends Negotiator {
  50 
  51     private static final boolean DEBUG =
  52         java.security.AccessController.doPrivileged(
  53               new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
  54 
  55     private GSSContext context;
  56     private byte[] oneToken;
  57 
  58     /**
  59      * Initialize the object, which includes:<ul>
  60      * <li>Find out what GSS mechanism to use from the system property
  61      * <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO
  62      * <li>Creating the GSSName for the target host, "HTTP/"+hostname
  63      * <li>Creating GSSContext
  64      * <li>A first call to initSecContext</ul>
  65      */
  66     private void init(HttpCallerInfo hci) throws GSSException {
  67         final Oid oid;
  68 
  69         if (hci.scheme.equalsIgnoreCase("Kerberos")) {
  70             // we can only use Kerberos mech when the scheme is kerberos
  71             oid = GSSUtil.GSS_KRB5_MECH_OID;
  72         } else {
  73             String pref = java.security.AccessController.doPrivileged(
  74                     new java.security.PrivilegedAction<String>() {
  75                         public String run() {
  76                             return System.getProperty(
  77                                 "http.auth.preference",
  78                                 "spnego");
  79                         }
  80                     });
  81             if (pref.equalsIgnoreCase("kerberos")) {
  82                 oid = GSSUtil.GSS_KRB5_MECH_OID;
  83             } else {
  84                 // currently there is no 3rd mech we can use
  85                 oid = GSSUtil.GSS_SPNEGO_MECH_OID;
  86             }
  87         }
  88 
  89         GSSManagerImpl manager = new GSSManagerImpl(
  90                 new HttpCaller(hci));
  91 
  92         // RFC 4559 4.1 uses uppercase service name "HTTP".
  93         // RFC 4120 6.2.1 demands the host be lowercase
  94         String peerName = "HTTP@" + hci.host.toLowerCase();
  95 
  96         GSSName serverName = manager.createName(peerName,
  97                 GSSName.NT_HOSTBASED_SERVICE);
  98         context = manager.createContext(serverName,
  99                                         oid,
 100                                         null,
 101                                         GSSContext.DEFAULT_LIFETIME);
 102 
 103         // In order to support credential delegation in HTTP/SPNEGO,
 104         // we always request it before initSecContext. The current
 105         // implementation will check the OK-AS-DELEGATE flag inside
 106         // the service ticket of the web server, and only enable
 107         // delegation when this flag is set. This check is only
 108         // performed when the GSS caller is CALLER_HTTP_NEGOTIATE,
 109         // so all other normal GSS-API calls are not affected.
 110 
 111         context.requestCredDeleg(true);
 112         oneToken = context.initSecContext(new byte[0], 0, 0);
 113     }
 114 
 115     /**
 116      * Constructor
 117      * @throws java.io.IOException If negotiator cannot be constructed
 118      */
 119     public NegotiatorImpl(HttpCallerInfo hci) throws IOException {
 120         try {
 121             init(hci);
 122         } catch (GSSException e) {
 123             if (DEBUG) {
 124                 System.out.println("Negotiate support not initiated, will " +
 125                         "fallback to other scheme if allowed. Reason:");
 126                 e.printStackTrace();
 127             }
 128             IOException ioe = new IOException("Negotiate support not initiated");
 129             ioe.initCause(e);
 130             throw ioe;
 131         }
 132     }
 133 
 134     /**
 135      * Return the first token of GSS, in SPNEGO, it's called NegTokenInit
 136      * @return the first token
 137      */
 138     @Override
 139     public byte[] firstToken() {
 140         return oneToken;
 141     }
 142 
 143     /**
 144      * Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg
 145      * @param token the token received from server
 146      * @return the next token
 147      * @throws java.io.IOException if the token cannot be created successfully
 148      */
 149     @Override
 150     public byte[] nextToken(byte[] token) throws IOException {
 151         try {
 152             return context.initSecContext(token, 0, token.length);
 153         } catch (GSSException e) {
 154             if (DEBUG) {
 155                 System.out.println("Negotiate support cannot continue. Reason:");
 156                 e.printStackTrace();
 157             }
 158             IOException ioe = new IOException("Negotiate support cannot continue");
 159             ioe.initCause(e);
 160             throw ioe;
 161         }
 162     }
 163 }
--- EOF ---