1 /* 2 * Copyright (c) 2000, 2012, 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.security.jgss.krb5; 27 28 import org.ietf.jgss.*; 29 import sun.security.jgss.GSSCaller; 30 import sun.security.jgss.spi.*; 31 import sun.security.krb5.*; 32 import sun.security.krb5.Config; 33 import javax.security.auth.kerberos.*; 34 import java.net.InetAddress; 35 import java.io.IOException; 36 import java.util.Date; 37 import java.security.AccessController; 38 import java.security.AccessControlContext; 39 import java.security.PrivilegedExceptionAction; 40 import java.security.PrivilegedActionException; 41 42 /** 43 * Implements the krb5 initiator credential element. 44 * 45 * @author Mayank Upadhyay 46 * @author Ram Marti 47 * @since 1.4 48 */ 49 50 public class Krb5InitCredential 51 extends KerberosTicket 52 implements Krb5CredElement { 53 54 private static final long serialVersionUID = 7723415700837898232L; 55 56 private Krb5NameElement name; 57 private Credentials krb5Credentials; 58 59 private Krb5InitCredential(Krb5NameElement name, 60 byte[] asn1Encoding, 61 KerberosPrincipal client, 62 KerberosPrincipal server, 63 byte[] sessionKey, 64 int keyType, 65 boolean[] flags, 66 Date authTime, 67 Date startTime, 68 Date endTime, 69 Date renewTill, 70 InetAddress[] clientAddresses) 71 throws GSSException { 72 super(asn1Encoding, 73 client, 74 server, 75 sessionKey, 76 keyType, 77 flags, 78 authTime, 79 startTime, 80 endTime, 81 renewTill, 82 clientAddresses); 83 84 this.name = name; 85 86 try { 87 // Cache this for later use by the sun.security.krb5 package. 88 krb5Credentials = new Credentials(asn1Encoding, 89 client.getName(), 90 server.getName(), 91 sessionKey, 92 keyType, 93 flags, 94 authTime, 95 startTime, 96 endTime, 97 renewTill, 98 clientAddresses); 99 } catch (KrbException e) { 100 throw new GSSException(GSSException.NO_CRED, -1, 101 e.getMessage()); 102 } catch (IOException e) { 103 throw new GSSException(GSSException.NO_CRED, -1, 104 e.getMessage()); 105 } 106 107 } 108 109 private Krb5InitCredential(Krb5NameElement name, 110 Credentials delegatedCred, 111 byte[] asn1Encoding, 112 KerberosPrincipal client, 113 KerberosPrincipal server, 114 byte[] sessionKey, 115 int keyType, 116 boolean[] flags, 117 Date authTime, 118 Date startTime, 119 Date endTime, 120 Date renewTill, 121 InetAddress[] clientAddresses) 122 throws GSSException { 123 super(asn1Encoding, 124 client, 125 server, 126 sessionKey, 127 keyType, 128 flags, 129 authTime, 130 startTime, 131 endTime, 132 renewTill, 133 clientAddresses); 134 135 this.name = name; 136 // A delegated cred does not have all fields set. So do not try to 137 // creat new Credentials out of the delegatedCred. 138 this.krb5Credentials = delegatedCred; 139 } 140 141 static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name, 142 int initLifetime) 143 throws GSSException { 144 145 KerberosTicket tgt = getTgt(caller, name, initLifetime); 146 if (tgt == null) 147 throw new GSSException(GSSException.NO_CRED, -1, 148 "Failed to find any Kerberos tgt"); 149 150 if (name == null) { 151 String fullName = tgt.getClient().getName(); 152 name = Krb5NameElement.getInstance(fullName, 153 Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); 154 } 155 156 return new Krb5InitCredential(name, 157 tgt.getEncoded(), 158 tgt.getClient(), 159 tgt.getServer(), 160 tgt.getSessionKey().getEncoded(), 161 tgt.getSessionKeyType(), 162 tgt.getFlags(), 163 tgt.getAuthTime(), 164 tgt.getStartTime(), 165 tgt.getEndTime(), 166 tgt.getRenewTill(), 167 tgt.getClientAddresses()); 168 } 169 170 static Krb5InitCredential getInstance(Krb5NameElement name, 171 Credentials delegatedCred) 172 throws GSSException { 173 174 EncryptionKey sessionKey = delegatedCred.getSessionKey(); 175 176 /* 177 * all of the following data is optional in a KRB-CRED 178 * messages. This check for each field. 179 */ 180 181 PrincipalName cPrinc = delegatedCred.getClient(); 182 PrincipalName sPrinc = delegatedCred.getServer(); 183 184 KerberosPrincipal client = null; 185 KerberosPrincipal server = null; 186 187 Krb5NameElement credName = null; 188 189 if (cPrinc != null) { 190 String fullName = cPrinc.getName(); 191 credName = Krb5NameElement.getInstance(fullName, 192 Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); 193 client = new KerberosPrincipal(fullName); 194 } 195 196 // XXX Compare name to credName 197 198 if (sPrinc != null) { 199 server = 200 new KerberosPrincipal(sPrinc.getName(), 201 KerberosPrincipal.KRB_NT_SRV_INST); 202 } 203 204 return new Krb5InitCredential(credName, 205 delegatedCred, 206 delegatedCred.getEncoded(), 207 client, 208 server, 209 sessionKey.getBytes(), 210 sessionKey.getEType(), 211 delegatedCred.getFlags(), 212 delegatedCred.getAuthTime(), 213 delegatedCred.getStartTime(), 214 delegatedCred.getEndTime(), 215 delegatedCred.getRenewTill(), 216 delegatedCred.getClientAddresses()); 217 } 218 219 /** 220 * Returns the principal name for this credential. The name 221 * is in mechanism specific format. 222 * 223 * @return GSSNameSpi representing principal name of this credential 224 * @exception GSSException may be thrown 225 */ 226 public final GSSNameSpi getName() throws GSSException { 227 return name; 228 } 229 230 /** 231 * Returns the init lifetime remaining. 232 * 233 * @return the init lifetime remaining in seconds 234 * @exception GSSException may be thrown 235 */ 236 public int getInitLifetime() throws GSSException { 237 int retVal = 0; 238 Date d = getEndTime(); 239 if (d == null) { 240 return 0; 241 } 242 retVal = (int)(d.getTime() - (new Date().getTime())); 243 244 return retVal/1000; 245 } 246 247 /** 248 * Returns the accept lifetime remaining. 249 * 250 * @return the accept lifetime remaining in seconds 251 * @exception GSSException may be thrown 252 */ 253 public int getAcceptLifetime() throws GSSException { 254 return 0; 255 } 256 257 public boolean isInitiatorCredential() throws GSSException { 258 return true; 259 } 260 261 public boolean isAcceptorCredential() throws GSSException { 262 return false; 263 } 264 265 /** 266 * Returns the oid representing the underlying credential 267 * mechanism oid. 268 * 269 * @return the Oid for this credential mechanism 270 * @exception GSSException may be thrown 271 */ 272 public final Oid getMechanism() { 273 return Krb5MechFactory.GSS_KRB5_MECH_OID; 274 } 275 276 public final java.security.Provider getProvider() { 277 return Krb5MechFactory.PROVIDER; 278 } 279 280 281 /** 282 * Returns a sun.security.krb5.Credentials instance so that it maybe 283 * used in that package for th Kerberos protocol. 284 */ 285 Credentials getKrb5Credentials() { 286 return krb5Credentials; 287 } 288 289 /* 290 * XXX Call to this.refresh() should refresh the locally cached copy 291 * of krb5Credentials also. 292 */ 293 294 /** 295 * Called to invalidate this credential element. 296 */ 297 public void dispose() throws GSSException { 298 try { 299 destroy(); 300 } catch (javax.security.auth.DestroyFailedException e) { 301 GSSException gssException = 302 new GSSException(GSSException.FAILURE, -1, 303 "Could not destroy credentials - " + e.getMessage()); 304 gssException.initCause(e); 305 } 306 } 307 308 // XXX call to this.destroy() should destroy the locally cached copy 309 // of krb5Credentials and then call super.destroy(). 310 311 private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name, 312 int initLifetime) 313 throws GSSException { 314 315 final String clientPrincipal; 316 317 /* 318 * Find the TGT for the realm that the client is in. If the client 319 * name is not available, then use the default realm. 320 */ 321 if (name != null) { 322 clientPrincipal = (name.getKrb5PrincipalName()).getName(); 323 } else { 324 clientPrincipal = null; 325 } 326 327 final AccessControlContext acc = AccessController.getContext(); 328 329 try { 330 final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN) 331 ? GSSCaller.CALLER_INITIATE 332 : caller; 333 return AccessController.doPrivileged( 334 new PrivilegedExceptionAction<KerberosTicket>() { 335 public KerberosTicket run() throws Exception { 336 // It's OK to use null as serverPrincipal. TGT is almost 337 // the first ticket for a principal and we use list. 338 return Krb5Util.getTicket( 339 realCaller, 340 clientPrincipal, null, acc); 341 }}); 342 } catch (PrivilegedActionException e) { 343 GSSException ge = 344 new GSSException(GSSException.NO_CRED, -1, 345 "Attempt to obtain new INITIATE credentials failed!" + 346 " (" + e.getMessage() + ")"); 347 ge.initCause(e.getException()); 348 throw ge; 349 } 350 } 351 352 @Override 353 public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException { 354 try { 355 Krb5NameElement kname = (Krb5NameElement)name; 356 Credentials newCred = Credentials.acquireS4U2selfCreds( 357 kname.getKrb5PrincipalName(), krb5Credentials); 358 return new Krb5ProxyCredential(this, kname, newCred.getTicket()); 359 } catch (IOException | KrbException ke) { 360 GSSException ge = 361 new GSSException(GSSException.FAILURE, -1, 362 "Attempt to obtain S4U2self credentials failed!"); 363 ge.initCause(ke); 364 throw ge; 365 } 366 } 367 }