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;
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 }
|
1 /*
2 * Copyright (c) 2001, 2019, 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 import java.util.Arrays;
37 import java.util.LinkedList;
38 import java.util.List;
39
40 /**
41 * This class is a utility that contains much of the TGS-Exchange
42 * protocol. It is used by ../Credentials.java for service ticket
43 * acquisition in both the normal and the x-realm case.
44 */
45 public class CredentialsUtil {
46
47 private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
48
49 /**
50 * Used by a middle server to acquire credentials on behalf of a
51 * client to itself using the S4U2self extension.
52 * @param client the client to impersonate
53 * @param ccreds the TGT of the middle service
54 * @return the new creds (cname=client, sname=middle)
55 */
56 public static Credentials acquireS4U2selfCreds(PrincipalName client,
57 Credentials ccreds) throws KrbException, IOException {
58 String uRealm = client.getRealmString();
59 String localRealm = ccreds.getClient().getRealmString();
60 if (!uRealm.equals(localRealm)) {
61 // TODO: we do not support kerberos referral now
62 throw new KrbException("Cross realm impersonation not supported");
63 }
64 if (!ccreds.isForwardable()) {
65 throw new KrbException("S4U2self needs a FORWARDABLE ticket");
66 }
67 Credentials creds = serviceCreds(KDCOptions.with(KDCOptions.FORWARDABLE),
68 ccreds, ccreds.getClient(), ccreds.getClient(), null,
69 new PAData[] {new PAData(Krb5.PA_FOR_USER,
70 new PAForUserEnc(client,
71 ccreds.getSessionKey()).asn1Encode())});
72 if (!creds.getClient().equals(client)) {
73 throw new KrbException("S4U2self request not honored by KDC");
74 }
75 if (!creds.isForwardable()) {
76 throw new KrbException("S4U2self ticket must be FORWARDABLE");
77 }
78 return creds;
79 }
80
81 /**
82 * Used by a middle server to acquire a service ticket to a backend
83 * server using the S4U2proxy extension.
84 * @param backend the name of the backend service
85 * @param second the client's service ticket to the middle server
86 * @param ccreds the TGT of the middle server
87 * @return the creds (cname=client, sname=backend)
88 */
89 public static Credentials acquireS4U2proxyCreds(
90 String backend, Ticket second,
91 PrincipalName client, Credentials ccreds)
92 throws KrbException, IOException {
93 Credentials creds = serviceCreds(KDCOptions.with(
94 KDCOptions.CNAME_IN_ADDL_TKT, KDCOptions.FORWARDABLE),
95 ccreds, ccreds.getClient(), new PrincipalName(backend),
96 new Ticket[] {second}, null);
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 PrincipalName.KRB_NT_SRV_HST);
119 return serviceCreds(sname, ccreds);
120 }
121
122 /**
123 * Gets a TGT to another realm
124 * @param localRealm this realm
125 * @param serviceRealm the other realm, cannot equals to localRealm
126 * @param ccreds TGT in this realm
127 * @param okAsDelegate an [out] argument to receive the okAsDelegate
128 * property. True only if all realms allow delegation.
129 * @return the TGT for the other realm, null if cannot find a path
130 * @throws KrbException if something goes wrong
131 */
132 private static Credentials getTGTforRealm(String localRealm,
133 String serviceRealm, Credentials ccreds, boolean[] okAsDelegate)
134 throws KrbException {
135
136 // Get a list of realms to traverse
137 String[] realms = Realm.getRealmsList(localRealm, serviceRealm);
138
139 int i = 0, k = 0;
140 Credentials cTgt = null, newTgt = null, theTgt = null;
244 else {
245 /*
246 * The new tgt's realm is not in the hierarchy of realms.
247 * It's probably not safe to get a tgt from
248 * a tgs that is outside the known list of realms.
249 * Give up now.
250 */
251 break;
252 }
253 } // Ends outermost/main 'for' loop
254
255 return theTgt;
256 }
257
258 /*
259 * This method does the real job to request the service credential.
260 */
261 private static Credentials serviceCreds(
262 PrincipalName service, Credentials ccreds)
263 throws KrbException, IOException {
264 return serviceCreds(new KDCOptions(), ccreds,
265 ccreds.getClient(), service, null, null);
266 }
267
268 private static Credentials serviceCreds(
269 KDCOptions options, Credentials asCreds,
270 PrincipalName cname, PrincipalName sname,
271 Ticket[] additionalTickets, PAData[] extraPAs)
272 throws KrbException, IOException {
273 if (!Config.DISABLE_REFERRALS) {
274 try {
275 return serviceCredsReferrals(options, asCreds,
276 cname, sname, additionalTickets, extraPAs);
277 } catch (KrbException e) {
278 // Server may raise an error if CANONICALIZE is true.
279 // Try CANONICALIZE false.
280 }
281 }
282 return serviceCredsSingle(options, asCreds,
283 cname, sname, additionalTickets, extraPAs);
284 }
285
286 private static Credentials serviceCredsReferrals(
287 KDCOptions options, Credentials asCreds,
288 PrincipalName cname, PrincipalName sname,
289 Ticket[] additionalTickets, PAData[] extraPAs)
290 throws KrbException, IOException {
291 options = new KDCOptions(options.toBooleanArray());
292 options.set(KDCOptions.CANONICALIZE, true);
293 PrincipalName cSname = (PrincipalName) sname.clone();
294 Credentials creds = null;
295 boolean isReferral = false;
296 List<String> referrals = new LinkedList<>();
297 while (referrals.size() <= Config.MAX_REFERRALS) {
298 ReferralsCache.ReferralCacheEntry ref =
299 ReferralsCache.get(sname, cSname.getRealmString());
300 String toRealm = null;
301 if (ref == null) {
302 creds = serviceCredsSingle(options, asCreds,
303 cname, cSname, additionalTickets, extraPAs);
304 PrincipalName server = creds.getServer();
305 if (!cSname.equals(server)) {
306 String[] serverNameStrings = server.getNameStrings();
307 if (serverNameStrings.length == 2 &&
308 serverNameStrings[0].equals(
309 PrincipalName.TGS_DEFAULT_SRV_NAME) &&
310 !cSname.getRealmAsString().equals(serverNameStrings[1])) {
311 // Server Name (sname) has the following format:
312 // krbtgt/TO-REALM.COM@FROM-REALM.COM
313 ReferralsCache.put(sname, server.getRealmString(),
314 serverNameStrings[1], creds);
315 toRealm = serverNameStrings[1];
316 isReferral = true;
317 asCreds = creds;
318 }
319 }
320 } else {
321 toRealm = ref.getToRealm();
322 asCreds = ref.getCreds();
323 isReferral = true;
324 }
325 if (isReferral) {
326 if (referrals.contains(toRealm)) {
327 // Referrals loop detected
328 return null;
329 }
330 cSname = new PrincipalName(cSname.getNameString(),
331 cSname.getNameType(), toRealm);
332 referrals.add(toRealm);
333 isReferral = false;
334 continue;
335 }
336 break;
337 }
338 return creds;
339 }
340
341 private static Credentials serviceCredsSingle(
342 KDCOptions options, Credentials asCreds,
343 PrincipalName cname, PrincipalName sname,
344 Ticket[] additionalTickets, PAData[] extraPAs)
345 throws KrbException, IOException {
346 Credentials theCreds = null;
347 boolean[] okAsDelegate = new boolean[]{true};
348 String[] serverAsCredsNames = asCreds.getServer().getNameStrings();
349 if (serverAsCredsNames.length == 2 &&
350 serverAsCredsNames[0].equals(
351 PrincipalName.TGS_DEFAULT_SRV_NAME)) {
352 String tgtRealm = serverAsCredsNames[1];
353 String serviceRealm = sname.getRealmString();
354 if (!serviceRealm.equals(tgtRealm)) {
355 // This is a cross-realm service request
356 if (DEBUG) {
357 System.out.println(">>> serviceCredsSingle:" +
358 " cross-realm authentication");
359 System.out.println(">>> serviceCredsSingle:" +
360 " obtaining credentials from " + tgtRealm +
361 " to " + serviceRealm);
362 }
363 Credentials newTgt = getTGTforRealm(tgtRealm, serviceRealm,
364 asCreds, okAsDelegate);
365 if (newTgt == null) {
366 throw new KrbApErrException(Krb5.KRB_AP_ERR_GEN_CRED,
367 "No service creds");
368 }
369 if (DEBUG) {
370 System.out.println(">>> Cross-realm TGT Credentials" +
371 " serviceCredsSingle: ");
372 Credentials.printDebug(newTgt);
373 }
374 asCreds = newTgt;
375 cname = asCreds.getClient();
376 } else if (DEBUG) {
377 System.out.println(">>> Credentials serviceCredsSingle:" +
378 " same realm");
379 }
380 }
381 KrbTgsReq req = new KrbTgsReq(options, asCreds,
382 cname, sname, additionalTickets, extraPAs);
383 theCreds = req.sendAndGetCreds();
384 if (theCreds != null) {
385 if (DEBUG) {
386 System.out.println(">>> TGS credentials serviceCredsSingle:");
387 Credentials.printDebug(theCreds);
388 }
389 if (!okAsDelegate[0]) {
390 theCreds.resetDelegate();
391 }
392 }
393 return theCreds;
394 }
395 }
|