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 
26 package sun.net.www.protocol.http.spnego;
27 
28 import com.sun.security.jgss.ExtendedGSSContext;
29 import java.io.IOException;
30 
31 import org.ietf.jgss.GSSContext;
32 import org.ietf.jgss.GSSException;
33 import org.ietf.jgss.GSSName;
34 import org.ietf.jgss.Oid;
35 
36 import sun.net.www.protocol.http.HttpCallerInfo;
37 import sun.net.www.protocol.http.Negotiator;
38 import sun.security.jgss.GSSManagerImpl;
39 import sun.security.jgss.GSSUtil;
40 import 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  */
50 public 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      */
init(HttpCallerInfo hci)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 ExtendedGSSContext) {
106             ((ExtendedGSSContext)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      */
NegotiatorImpl(HttpCallerInfo hci)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
firstToken()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
nextToken(byte[] token)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