1/* 2 * Copyright (c) 2005, 2009, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.net.www.protocol.http.spnego; 27 28import java.io.IOException; 29 30import org.ietf.jgss.GSSContext; 31import org.ietf.jgss.GSSException; 32import org.ietf.jgss.GSSName; 33import org.ietf.jgss.Oid; 34 35import sun.net.www.protocol.http.HttpCallerInfo; 36import sun.net.www.protocol.http.Negotiator; 37import sun.security.jgss.GSSManagerImpl; 38import sun.security.jgss.GSSContextImpl; 39import sun.security.jgss.GSSUtil; 40import sun.security.jgss.HttpCaller; 41 42/** 43 * This class encapsulates all JAAS and JGSS API calls in a separate class 44 * outside NegotiateAuthentication.java so that J2SE build can go smoothly 45 * without the presence of it. 46 * 47 * @author weijun.wang@sun.com 48 * @since 1.6 49 */ 50public class NegotiatorImpl extends Negotiator { 51 52 private static final boolean DEBUG = 53 java.security.AccessController.doPrivileged( 54 new sun.security.action.GetBooleanAction("sun.security.krb5.debug")); 55 56 private GSSContext context; 57 private byte[] oneToken; 58 59 /** 60 * Initialize the object, which includes:<ul> 61 * <li>Find out what GSS mechanism to use from the system property 62 * <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO 63 * <li>Creating the GSSName for the target host, "HTTP/"+hostname 64 * <li>Creating GSSContext 65 * <li>A first call to initSecContext</ul> 66 */ 67 private void init(HttpCallerInfo hci) throws GSSException { 68 final Oid oid; 69 70 if (hci.scheme.equalsIgnoreCase("Kerberos")) { 71 // we can only use Kerberos mech when the scheme is kerberos 72 oid = GSSUtil.GSS_KRB5_MECH_OID; 73 } else { 74 String pref = java.security.AccessController.doPrivileged( 75 new java.security.PrivilegedAction<String>() { 76 public String run() { 77 return System.getProperty( 78 "http.auth.preference", 79 "spnego"); 80 } 81 }); 82 if (pref.equalsIgnoreCase("kerberos")) { 83 oid = GSSUtil.GSS_KRB5_MECH_OID; 84 } else { 85 // currently there is no 3rd mech we can use 86 oid = GSSUtil.GSS_SPNEGO_MECH_OID; 87 } 88 } 89 90 GSSManagerImpl manager = new GSSManagerImpl( 91 new HttpCaller(hci)); 92 93 // RFC 4559 4.1 uses uppercase service name "HTTP". 94 // RFC 4120 6.2.1 demands the host be lowercase 95 String peerName = "HTTP@" + hci.host.toLowerCase(); 96 97 GSSName serverName = manager.createName(peerName, 98 GSSName.NT_HOSTBASED_SERVICE); 99 context = manager.createContext(serverName, 100 oid, 101 null, 102 GSSContext.DEFAULT_LIFETIME); 103 104 // Always respect delegation policy in HTTP/SPNEGO. 105 if (context instanceof GSSContextImpl) { 106 ((GSSContextImpl)context).requestDelegPolicy(true); 107 } 108 oneToken = context.initSecContext(new byte[0], 0, 0); 109 } 110 111 /** 112 * Constructor 113 * @throws java.io.IOException If negotiator cannot be constructed 114 */ 115 public NegotiatorImpl(HttpCallerInfo hci) throws IOException { 116 try { 117 init(hci); 118 } catch (GSSException e) { 119 if (DEBUG) { 120 System.out.println("Negotiate support not initiated, will " + 121 "fallback to other scheme if allowed. Reason:"); 122 e.printStackTrace(); 123 } 124 IOException ioe = new IOException("Negotiate support not initiated"); 125 ioe.initCause(e); 126 throw ioe; 127 } 128 } 129 130 /** 131 * Return the first token of GSS, in SPNEGO, it's called NegTokenInit 132 * @return the first token 133 */ 134 @Override 135 public byte[] firstToken() { 136 return oneToken; 137 } 138 139 /** 140 * Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg 141 * @param token the token received from server 142 * @return the next token 143 * @throws java.io.IOException if the token cannot be created successfully 144 */ 145 @Override 146 public byte[] nextToken(byte[] token) throws IOException { 147 try { 148 return context.initSecContext(token, 0, token.length); 149 } catch (GSSException e) { 150 if (DEBUG) { 151 System.out.println("Negotiate support cannot continue. Reason:"); 152 e.printStackTrace(); 153 } 154 IOException ioe = new IOException("Negotiate support cannot continue"); 155 ioe.initCause(e); 156 throw ioe; 157 } 158 } 159} 160