59 throw new KrbException("Cross realm impersonation not supported"); |
61 throw new KrbException("Cross realm impersonation not supported"); |
60 } |
62 } |
61 if (!ccreds.isForwardable()) { |
63 if (!ccreds.isForwardable()) { |
62 throw new KrbException("S4U2self needs a FORWARDABLE ticket"); |
64 throw new KrbException("S4U2self needs a FORWARDABLE ticket"); |
63 } |
65 } |
64 KrbTgsReq req = new KrbTgsReq( |
66 Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE), |
65 ccreds, |
67 ccreds, ccreds.getClient(), ccreds.getClient(), null, |
66 ccreds.getClient(), |
68 new PAData[] {new PAData(Krb5.PA_FOR_USER, |
67 new PAData(Krb5.PA_FOR_USER, |
69 new PAForUserEnc(client, |
68 new PAForUserEnc(client, |
70 ccreds.getSessionKey()).asn1Encode())}); |
69 ccreds.getSessionKey()).asn1Encode())); |
|
70 Credentials creds = req.sendAndGetCreds(); |
|
71 if (!creds.getClient().equals(client)) { |
71 if (!creds.getClient().equals(client)) { |
72 throw new KrbException("S4U2self request not honored by KDC"); |
72 throw new KrbException("S4U2self request not honored by KDC"); |
73 } |
73 } |
74 if (!creds.isForwardable()) { |
74 if (!creds.isForwardable()) { |
75 throw new KrbException("S4U2self ticket must be FORWARDABLE"); |
75 throw new KrbException("S4U2self ticket must be FORWARDABLE"); |
112 * @param ccreds client's initial credential |
111 * @param ccreds client's initial credential |
113 */ |
112 */ |
114 public static Credentials acquireServiceCreds( |
113 public static Credentials acquireServiceCreds( |
115 String service, Credentials ccreds) |
114 String service, Credentials ccreds) |
116 throws KrbException, IOException { |
115 throws KrbException, IOException { |
117 PrincipalName sname = new PrincipalName(service); |
116 PrincipalName sname = new PrincipalName(service, |
118 String serviceRealm = sname.getRealmString(); |
117 PrincipalName.KRB_NT_SRV_HST); |
119 String localRealm = ccreds.getClient().getRealmString(); |
118 return serviceCreds(sname, ccreds); |
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 } |
119 } |
165 |
120 |
166 /** |
121 /** |
167 * Gets a TGT to another realm |
122 * Gets a TGT to another realm |
168 * @param localRealm this realm |
123 * @param localRealm this realm |
303 * This method does the real job to request the service credential. |
258 * This method does the real job to request the service credential. |
304 */ |
259 */ |
305 private static Credentials serviceCreds( |
260 private static Credentials serviceCreds( |
306 PrincipalName service, Credentials ccreds) |
261 PrincipalName service, Credentials ccreds) |
307 throws KrbException, IOException { |
262 throws KrbException, IOException { |
308 return new KrbTgsReq(ccreds, service).sendAndGetCreds(); |
263 return serviceCreds(new KDCOptions(), ccreds, |
|
264 ccreds.getClient(), service, null, null); |
|
265 } |
|
266 |
|
267 /* |
|
268 * Obtains credentials for a service (TGS). |
|
269 * Cross-realm referrals are handled if enabled. A fallback scheme |
|
270 * without cross-realm referrals supports is used in case of server |
|
271 * error to maintain backward compatibility. |
|
272 */ |
|
273 private static Credentials serviceCreds( |
|
274 KDCOptions options, Credentials asCreds, |
|
275 PrincipalName cname, PrincipalName sname, |
|
276 Ticket[] additionalTickets, PAData[] extraPAs) |
|
277 throws KrbException, IOException { |
|
278 if (!Config.DISABLE_REFERRALS) { |
|
279 try { |
|
280 return serviceCredsReferrals(options, asCreds, |
|
281 cname, sname, additionalTickets, extraPAs); |
|
282 } catch (KrbException e) { |
|
283 // Server may raise an error if CANONICALIZE is true. |
|
284 // Try CANONICALIZE false. |
|
285 } |
|
286 } |
|
287 return serviceCredsSingle(options, asCreds, |
|
288 cname, sname, additionalTickets, extraPAs); |
|
289 } |
|
290 |
|
291 /* |
|
292 * Obtains credentials for a service (TGS). |
|
293 * May handle and follow cross-realm referrals as defined by RFC 6806. |
|
294 */ |
|
295 private static Credentials serviceCredsReferrals( |
|
296 KDCOptions options, Credentials asCreds, |
|
297 PrincipalName cname, PrincipalName sname, |
|
298 Ticket[] additionalTickets, PAData[] extraPAs) |
|
299 throws KrbException, IOException { |
|
300 options = new KDCOptions(options.toBooleanArray()); |
|
301 options.set(KDCOptions.CANONICALIZE, true); |
|
302 PrincipalName cSname = sname; |
|
303 Credentials creds = null; |
|
304 boolean isReferral = false; |
|
305 List<String> referrals = new LinkedList<>(); |
|
306 while (referrals.size() <= Config.MAX_REFERRALS) { |
|
307 ReferralsCache.ReferralCacheEntry ref = |
|
308 ReferralsCache.get(sname, cSname.getRealmString()); |
|
309 String toRealm = null; |
|
310 if (ref == null) { |
|
311 creds = serviceCredsSingle(options, asCreds, |
|
312 cname, cSname, additionalTickets, extraPAs); |
|
313 PrincipalName server = creds.getServer(); |
|
314 if (!cSname.equals(server)) { |
|
315 String[] serverNameStrings = server.getNameStrings(); |
|
316 if (serverNameStrings.length == 2 && |
|
317 serverNameStrings[0].equals( |
|
318 PrincipalName.TGS_DEFAULT_SRV_NAME) && |
|
319 !cSname.getRealmAsString().equals(serverNameStrings[1])) { |
|
320 // Server Name (sname) has the following format: |
|
321 // krbtgt/TO-REALM.COM@FROM-REALM.COM |
|
322 ReferralsCache.put(sname, server.getRealmString(), |
|
323 serverNameStrings[1], creds); |
|
324 toRealm = serverNameStrings[1]; |
|
325 isReferral = true; |
|
326 asCreds = creds; |
|
327 } |
|
328 } |
|
329 } else { |
|
330 toRealm = ref.getToRealm(); |
|
331 asCreds = ref.getCreds(); |
|
332 isReferral = true; |
|
333 } |
|
334 if (isReferral) { |
|
335 if (referrals.contains(toRealm)) { |
|
336 // Referrals loop detected |
|
337 return null; |
|
338 } |
|
339 cSname = new PrincipalName(cSname.getNameString(), |
|
340 cSname.getNameType(), toRealm); |
|
341 referrals.add(toRealm); |
|
342 isReferral = false; |
|
343 continue; |
|
344 } |
|
345 break; |
|
346 } |
|
347 return creds; |
|
348 } |
|
349 |
|
350 /* |
|
351 * Obtains credentials for a service (TGS). |
|
352 * If the service realm is different than the one in the TGT, a new TGT for |
|
353 * the service realm is obtained first (see getTGTforRealm call). This is |
|
354 * not expected when following cross-realm referrals because the referral |
|
355 * TGT realm matches the service realm. |
|
356 */ |
|
357 private static Credentials serviceCredsSingle( |
|
358 KDCOptions options, Credentials asCreds, |
|
359 PrincipalName cname, PrincipalName sname, |
|
360 Ticket[] additionalTickets, PAData[] extraPAs) |
|
361 throws KrbException, IOException { |
|
362 Credentials theCreds = null; |
|
363 boolean[] okAsDelegate = new boolean[]{true}; |
|
364 String[] serverAsCredsNames = asCreds.getServer().getNameStrings(); |
|
365 String tgtRealm = serverAsCredsNames[1]; |
|
366 String serviceRealm = sname.getRealmString(); |
|
367 if (!serviceRealm.equals(tgtRealm)) { |
|
368 // This is a cross-realm service request |
|
369 if (DEBUG) { |
|
370 System.out.println(">>> serviceCredsSingle:" + |
|
371 " cross-realm authentication"); |
|
372 System.out.println(">>> serviceCredsSingle:" + |
|
373 " obtaining credentials from " + tgtRealm + |
|
374 " to " + serviceRealm); |
|
375 } |
|
376 Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm, |
|
377 asCreds, okAsDelegate); |
|
378 if (newTgt == null) { |
|
379 throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED, |
|
380 "No service creds"); |
|
381 } |
|
382 if (DEBUG) { |
|
383 System.out.println(">>> Cross-realm TGT Credentials" + |
|
384 " serviceCredsSingle: "); |
|
385 Credentials.printDebug(newTgt); |
|
386 } |
|
387 asCreds = newTgt; |
|
388 cname = asCreds.getClient(); |
|
389 } else if (DEBUG) { |
|
390 System.out.println(">>> Credentials serviceCredsSingle:" + |
|
391 " same realm"); |
|
392 } |
|
393 KrbTgsReq req = new KrbTgsReq(options, asCreds, |
|
394 cname, sname, additionalTickets, extraPAs); |
|
395 theCreds = req.sendAndGetCreds(); |
|
396 if (theCreds != null) { |
|
397 if (DEBUG) { |
|
398 System.out.println(">>> TGS credentials serviceCredsSingle:"); |
|
399 Credentials.printDebug(theCreds); |
|
400 } |
|
401 if (!okAsDelegate[0]) { |
|
402 theCreds.resetDelegate(); |
|
403 } |
|
404 } |
|
405 return theCreds; |
309 } |
406 } |
310 } |
407 } |