1 /* 2 * Copyright (c) 2001, 2013, 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 /* 27 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32 package sun.security.krb5.internal; 33 34 import sun.security.krb5.*; 35 import java.io.IOException; 36 37 /** 38 * This class is a utility that contains much of the TGS-Exchange 39 * protocol. It is used by ../Credentials.java for service ticket 40 * acquisition in both the normal and the x-realm case. 41 */ 42 public class CredentialsUtil { 43 44 private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; 45 46 /** 47 * Used by a middle server to acquire credentials on behalf of a 48 * client to itself using the S4U2self extension. 49 * @param client the client to impersonate 50 * @param ccreds the TGT of the middle service 51 * @return the new creds (cname=client, sname=middle) 52 */ 53 public static Credentials acquireS4U2selfCreds(PrincipalName client, 54 Credentials ccreds) throws KrbException, IOException { 55 String uRealm = client.getRealmString(); 56 String localRealm = ccreds.getClient().getRealmString(); 57 if (!uRealm.equals(localRealm)) { 58 // TODO: we do not support kerberos referral now 59 throw new KrbException("Cross realm impersonation not supported"); 60 } 61 if (!ccreds.isForwardable()) { 62 throw new KrbException("S4U2self needs a FORWARDABLE ticket"); 63 } 64 KrbTgsReq req = new KrbTgsReq( 65 ccreds, 66 ccreds.getClient(), 67 new PAData(Krb5.PA_FOR_USER, 68 new PAForUserEnc(client, 69 ccreds.getSessionKey()).asn1Encode())); 70 Credentials creds = req.sendAndGetCreds(); 71 if (!creds.getClient().equals(client)) { 72 throw new KrbException("S4U2self request not honored by KDC"); 73 } 74 if (!creds.isForwardable()) { 75 throw new KrbException("S4U2self ticket must be FORWARDABLE"); 76 } 77 return creds; 78 } 79 80 /** 81 * Used by a middle server to acquire a service ticket to a backend 82 * server using the S4U2proxy extension. 83 * @param backend the name of the backend service 84 * @param second the client's service ticket to the middle server 85 * @param ccreds the TGT of the middle server 86 * @return the creds (cname=client, sname=backend) 87 */ 88 public static Credentials acquireS4U2proxyCreds( 89 String backend, Ticket second, 90 PrincipalName client, Credentials ccreds) 91 throws KrbException, IOException { 92 KrbTgsReq req = new KrbTgsReq( 93 ccreds, 94 second, 95 new PrincipalName(backend)); 96 Credentials creds = req.sendAndGetCreds(); 97 if (!creds.getClient().equals(client)) { 98 throw new KrbException("S4U2proxy request not honored by KDC"); 99 } 100 return creds; 101 } 102 103 /** 104 * Acquires credentials for a specified service using initial 105 * credential. When the service has a different realm from the initial 106 * credential, we do cross-realm authentication - first, we use the 107 * current credential to get a cross-realm credential from the local KDC, 108 * then use that cross-realm credential to request service credential 109 * from the foreign KDC. 110 * 111 * @param service the name of service principal 112 * @param ccreds client's initial credential 113 */ 114 public static Credentials acquireServiceCreds( 115 String service, Credentials ccreds) 116 throws KrbException, IOException { 117 PrincipalName sname = new PrincipalName(service); 118 String serviceRealm = sname.getRealmString(); 119 String localRealm = ccreds.getClient().getRealmString(); 120 121 if (localRealm.equals(serviceRealm)) { 122 if (DEBUG) { 123 System.out.println( 124 ">>> Credentials acquireServiceCreds: same realm"); 125 } 126 return serviceCreds(sname, ccreds); 127 } 128 Credentials theCreds = null; 129 130 boolean[] okAsDelegate = new boolean[1]; 131 Credentials theTgt = getTGTforRealm(localRealm, serviceRealm, 132 ccreds, okAsDelegate); 133 if (theTgt != null) { 134 if (DEBUG) { 135 System.out.println(">>> Credentials acquireServiceCreds: " 136 + "got right tgt"); 137 System.out.println(">>> Credentials acquireServiceCreds: " 138 + "obtaining service creds for " + sname); 139 } 140 141 try { 142 theCreds = serviceCreds(sname, theTgt); 143 } catch (Exception exc) { 144 if (DEBUG) { 145 System.out.println(exc); 146 } 147 theCreds = null; 148 } 149 } 150 151 if (theCreds != null) { 152 if (DEBUG) { 153 System.out.println(">>> Credentials acquireServiceCreds: " 154 + "returning creds:"); 155 Credentials.printDebug(theCreds); 156 } 157 if (!okAsDelegate[0]) { 158 theCreds.resetDelegate(); 159 } 160 return theCreds; 161 } 162 throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, 163 "No service creds"); 164 } 165 166 /** 167 * Gets a TGT to another realm 168 * @param localRealm this realm 169 * @param serviceRealm the other realm, cannot equals to localRealm 170 * @param ccreds TGT in this realm 171 * @param okAsDelegate an [out] argument to receive the okAsDelegate 172 * property. True only if all realms allow delegation. 173 * @return the TGT for the other realm, null if cannot find a path 174 * @throws KrbException if something goes wrong 175 */ 176 private static Credentials getTGTforRealm(String localRealm, 177 String serviceRealm, Credentials ccreds, boolean[] okAsDelegate) 178 throws KrbException { 179 180 // Get a list of realms to traverse 181 String[] realms = Realm.getRealmsList(localRealm, serviceRealm); 182 183 int i = 0, k = 0; 184 Credentials cTgt = null, newTgt = null, theTgt = null; 185 PrincipalName tempService = null; 186 String newTgtRealm = null; 187 188 okAsDelegate[0] = true; 189 for (cTgt = ccreds, i = 0; i < realms.length;) { 190 tempService = PrincipalName.tgsService(serviceRealm, realms[i]); 191 192 if (DEBUG) { 193 System.out.println( 194 ">>> Credentials acquireServiceCreds: main loop: [" 195 + i +"] tempService=" + tempService); 196 } 197 198 try { 199 newTgt = serviceCreds(tempService, cTgt); 200 } catch (Exception exc) { 201 newTgt = null; 202 } 203 204 if (newTgt == null) { 205 if (DEBUG) { 206 System.out.println(">>> Credentials acquireServiceCreds: " 207 + "no tgt; searching thru capath"); 208 } 209 210 /* 211 * No tgt found. Let's go thru the realms list one by one. 212 */ 213 for (newTgt = null, k = i+1; 214 newTgt == null && k < realms.length; k++) { 215 tempService = PrincipalName.tgsService(realms[k], realms[i]); 216 if (DEBUG) { 217 System.out.println( 218 ">>> Credentials acquireServiceCreds: " 219 + "inner loop: [" + k 220 + "] tempService=" + tempService); 221 } 222 try { 223 newTgt = serviceCreds(tempService, cTgt); 224 } catch (Exception exc) { 225 newTgt = null; 226 } 227 } 228 } // Ends 'if (newTgt == null)' 229 230 if (newTgt == null) { 231 if (DEBUG) { 232 System.out.println(">>> Credentials acquireServiceCreds: " 233 + "no tgt; cannot get creds"); 234 } 235 break; 236 } 237 238 /* 239 * We have a tgt. It may or may not be for the target. 240 * If it's for the target realm, we're done looking for a tgt. 241 */ 242 newTgtRealm = newTgt.getServer().getInstanceComponent(); 243 if (okAsDelegate[0] && !newTgt.checkDelegate()) { 244 if (DEBUG) { 245 System.out.println(">>> Credentials acquireServiceCreds: " + 246 "global OK-AS-DELEGATE turned off at " + 247 newTgt.getServer()); 248 } 249 okAsDelegate[0] = false; 250 } 251 252 if (DEBUG) { 253 System.out.println(">>> Credentials acquireServiceCreds: " 254 + "got tgt"); 255 } 256 257 if (newTgtRealm.equals(serviceRealm)) { 258 /* We got the right tgt */ 259 theTgt = newTgt; 260 break; 261 } 262 263 /* 264 * The new tgt is not for the target realm. 265 * See if the realm of the new tgt is in the list of realms 266 * and continue looking from there. 267 */ 268 for (k = i+1; k < realms.length; k++) { 269 if (newTgtRealm.equals(realms[k])) { 270 break; 271 } 272 } 273 274 if (k < realms.length) { 275 /* 276 * (re)set the counter so we start looking 277 * from the realm we just obtained a tgt for. 278 */ 279 i = k; 280 cTgt = newTgt; 281 282 if (DEBUG) { 283 System.out.println(">>> Credentials acquireServiceCreds: " 284 + "continuing with main loop counter reset to " + i); 285 } 286 continue; 287 } 288 else { 289 /* 290 * The new tgt's realm is not in the hierarchy of realms. 291 * It's probably not safe to get a tgt from 292 * a tgs that is outside the known list of realms. 293 * Give up now. 294 */ 295 break; 296 } 297 } // Ends outermost/main 'for' loop 298 299 return theTgt; 300 } 301 302 /* 303 * This method does the real job to request the service credential. 304 */ 305 private static Credentials serviceCreds( 306 PrincipalName service, Credentials ccreds) 307 throws KrbException, IOException { 308 return new KrbTgsReq(ccreds, service).sendAndGetCreds(); 309 } 310 }