001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.auth.jgss.kerberos;
019:
020: import java.lang.reflect.Constructor;
021: import java.security.AccessControlContext;
022: import java.security.AccessController;
023: import java.security.PrivilegedAction;
024: import java.util.ArrayList;
025: import java.util.Set;
026:
027: import javax.security.auth.DestroyFailedException;
028: import javax.security.auth.RefreshFailedException;
029: import javax.security.auth.Subject;
030: import javax.security.auth.kerberos.KerberosKey;
031: import javax.security.auth.kerberos.KerberosPrincipal;
032: import javax.security.auth.kerberos.KerberosTicket;
033: import javax.security.auth.kerberos.ServicePermission;
034: import javax.security.auth.login.LoginContext;
035: import javax.security.auth.login.LoginException;
036:
037: import org.apache.harmony.auth.jgss.kerberos.toolbox.KerberosToolboxSpi;
038: import org.ietf.jgss.GSSException;
039: import org.ietf.jgss.GSSName;
040: import org.ietf.jgss.Oid;
041:
042: public class KerberosUtils {
043: public static final String DEFAULT_CHARSET_NAME = "UTF-8";
044:
045: public static final int DEFAULT_GSSEXCEPTION_MAJOR_CODE = 3;
046:
047: public static final int DEFAULT_GSSEXCEPTION_MINOR_CODE = 0;
048:
049: public static final Oid KRB5_MECH;
050:
051: public static final Oid KRB5_PRINCIPAL_NAMETYPE;
052:
053: public static final Oid[] SUPPORTED_NAME_MECHS;
054:
055: public static final String KERBEROS_TOOLBOX_PROVIDER = "org.apache.harmony.auth.jgss.kerberos.toolbox.KerberosToolboxImpl";
056:
057: public static final String KERBEROS_CONTEXT_INIT = "org.apache.harmony.auth.jgss.initiate";
058:
059: public static final String KERBEROS_CONTEXT_ACCEPT = "org.apache.harmony.auth.jgss.accept";
060:
061: public static final String SERVICE_PERMISSION_ACTION_INITIATE = "initiate";
062:
063: public static final String SERVICE_PERMISSION_ACTION_ACCEPT = "accept";
064:
065: public static final String[] SUPPORTED_KEY_ENCRYPT = { "DES" };
066:
067: static {
068: try {
069: KRB5_MECH = new Oid("1.2.840.113554.1.2.2");
070: KRB5_PRINCIPAL_NAMETYPE = new Oid("1.2.840.113554.1.2.2.1");
071:
072: } catch (GSSException e) {
073: throw new Error();
074: }
075: SUPPORTED_NAME_MECHS = new Oid[] { GSSName.NT_USER_NAME,
076: GSSName.NT_HOSTBASED_SERVICE, GSSName.NT_EXPORT_NAME,
077: KRB5_PRINCIPAL_NAMETYPE };
078: }
079:
080: public static KerberosToolboxSpi getKerberosToolbox(String kdcName)
081: throws Exception {
082: Class cls = Class.forName(KERBEROS_TOOLBOX_PROVIDER);
083: Constructor constructor = cls.getConstructor(String.class);
084: return (KerberosToolboxSpi) constructor.newInstance(kdcName);
085: }
086:
087: private static KerberosTicket getKerberosTicketFromContext(
088: final KerberosPrincipal clientPrincipal,
089: final KerberosPrincipal serverPrincipal) {
090: AccessControlContext acc = AccessController.getContext();
091: KerberosTicket tgt = AccessController.doPrivileged(
092: new PrivilegedAction<KerberosTicket>() {
093:
094: public KerberosTicket run() {
095: AccessControlContext acc = AccessController
096: .getContext();
097: Subject subject = Subject.getSubject(acc);
098: return getTicketFromSubject(subject,
099: clientPrincipal, serverPrincipal);
100: }
101: }, acc);
102: if (tgt != null) {
103: checkTGTServicePermission(tgt);
104: }
105: return tgt;
106: }
107:
108: private static KerberosKey[] getKeysFromContext(
109: final KerberosPrincipal serverPrincipal) {
110: AccessControlContext acc = AccessController.getContext();
111: KerberosKey[] kerberosKeys = AccessController.doPrivileged(
112: new PrivilegedAction<KerberosKey[]>() {
113: public KerberosKey[] run() {
114: AccessControlContext acc = AccessController
115: .getContext();
116: Subject subject = Subject.getSubject(acc);
117: return getKeysFromSubject(subject,
118: serverPrincipal);
119: }
120: }, acc);
121: if (kerberosKeys.length > 0) {
122: //All keys in kerberosKeys have the same principal. Check the permission for the first key is enough.
123: checkServerKeyServicePermission(kerberosKeys[0]);
124: return kerberosKeys;
125: }
126: return null;
127: }
128:
129: private static KerberosPrincipal getPrincipalFromContext() {
130: AccessControlContext acc = AccessController.getContext();
131: return AccessController.doPrivileged(
132: new PrivilegedAction<KerberosPrincipal>() {
133: public KerberosPrincipal run() {
134: AccessControlContext acc = AccessController
135: .getContext();
136: Subject subject = Subject.getSubject(acc);
137: Set<KerberosPrincipal> kerberosPrincipals = subject
138: .getPrincipals(KerberosPrincipal.class);
139: if (kerberosPrincipals.size() == 0) {
140: return null;
141: }
142: return kerberosPrincipals.iterator().next();
143: }
144: }, acc);
145: }
146:
147: private static KerberosKey[] getKeysFromSubject(Subject subject,
148: final KerberosPrincipal serverPrincipal) {
149: Set<KerberosKey> kerberosKeys = subject
150: .getPrivateCredentials(KerberosKey.class);
151: ArrayList<KerberosKey> serverKeys = new ArrayList<KerberosKey>();
152: for (KerberosKey kerberosKey : kerberosKeys) {
153: if (serverPrincipal.equals(kerberosKey.getPrincipal())) {
154: serverKeys.add(kerberosKey);
155: }
156: }
157: return serverKeys.toArray(new KerberosKey[serverKeys.size()]);
158: }
159:
160: private static KerberosTicket getTicketFromSubject(Subject subject,
161: final KerberosPrincipal clientPrincipal,
162: final KerberosPrincipal serverPrincipal) {
163: if (null == subject) {
164: return null;
165: }
166: Set<KerberosTicket> kerberosTickets = subject
167: .getPrivateCredentials(KerberosTicket.class);
168: for (KerberosTicket tgt : kerberosTickets) {
169: if (clientPrincipal.equals(tgt.getClient())
170: && serverPrincipal.equals(tgt.getServer())) {
171: if (isCurrent(tgt)) {
172: return tgt;
173: }
174:
175: // the kerberosTicket cannot be renewed. Just
176: // discard it
177: // from the subject's private credentials.
178: kerberosTickets.remove(tgt);
179: return null;
180: }
181: }
182: return null;
183: }
184:
185: private static boolean isCurrent(KerberosTicket ticket) {
186: if (!ticket.isCurrent()) {
187: try {
188: ticket.refresh();
189: } catch (RefreshFailedException e) {
190: try {
191: ticket.destroy();
192: } catch (DestroyFailedException e1) {
193: e1.printStackTrace();
194: }
195: return false;
196: }
197: }
198: return true;
199: }
200:
201: private static KerberosTicket getTGTFromLoginModule(
202: KerberosPrincipal clientPrincipal) {
203: LoginContext loginContext = null;
204: try {
205: loginContext = new LoginContext(KERBEROS_CONTEXT_INIT);
206: loginContext.login();
207:
208: } catch (LoginException e) {
209: e.printStackTrace();
210: return null;
211: }
212: Subject subject = loginContext.getSubject();
213: if (clientPrincipal == null) {
214: clientPrincipal = getPrincipalFromContext();
215: }
216: return getTicketFromSubject(subject, clientPrincipal,
217: getTGTServerPrincipal(clientPrincipal));
218: }
219:
220: private static KerberosKey[] getKeysFromLoginModule(
221: KerberosPrincipal serverPrincipal) {
222: LoginContext loginContext = null;
223: try {
224: loginContext = new LoginContext(KERBEROS_CONTEXT_ACCEPT);
225: loginContext.login();
226:
227: } catch (LoginException e) {
228: e.printStackTrace();
229: return null;
230: }
231: Subject subject = loginContext.getSubject();
232: if (serverPrincipal == null) {
233: serverPrincipal = getPrincipalFromContext();
234: }
235: return getKeysFromSubject(subject, serverPrincipal);
236: }
237:
238: private static KerberosPrincipal getTGTServerPrincipal(
239: KerberosPrincipal clientPrincipal) {
240: String realm = clientPrincipal.getRealm();
241: return new KerberosPrincipal("krbtgt/" + realm + "@" + realm);
242: }
243:
244: public static KerberosTicket getTGT(
245: KerberosPrincipal clientPrincipal) {
246: KerberosTicket tgt = null;
247: if (clientPrincipal != null) {
248: tgt = getKerberosTicketFromContext(clientPrincipal,
249: getTGTServerPrincipal(clientPrincipal));
250: }
251: if (null != tgt) {
252: return tgt;
253: }
254: tgt = getTGTFromLoginModule(clientPrincipal);
255: if (null != tgt) {
256: // TODO CACHE : Whether should attach this tgt to the subject for
257: // current AccessControlContext?
258: }
259: return tgt;
260: }
261:
262: public static KerberosKey[] getKeys(
263: KerberosPrincipal serverPrincipal) {
264: KerberosKey[] keys = null;
265: if (serverPrincipal != null) {
266: keys = getKeysFromContext(serverPrincipal);
267: }
268: if (null != keys) {
269: return keys;
270: }
271: keys = getKeysFromLoginModule(serverPrincipal);
272: if (null != keys) {
273: // TODO CACHE : Whether should attach these keys to the subject for
274: // current AccessControlContext?
275: }
276: return keys;
277: }
278:
279: public static void checkTGTServicePermission(KerberosTicket tgt) {
280: checkServicePermission(tgt.getServer(),
281: SERVICE_PERMISSION_ACTION_INITIATE);
282: }
283:
284: public static void checkServerKeyServicePermission(KerberosKey key) {
285: checkServicePermission(key.getPrincipal(),
286: SERVICE_PERMISSION_ACTION_ACCEPT);
287: }
288:
289: public static void checkServicePermission(
290: KerberosPrincipal principal, String action) {
291: SecurityManager sm = System.getSecurityManager();
292: if (sm == null) {
293: return;
294: }
295: ServicePermission servicePermission = new ServicePermission(
296: principal.getName(), action);
297: sm.checkPermission(servicePermission);
298: }
299: }
|