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 }