View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.wss4j.common.kerberos;
21  
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.security.Key;
25  import java.security.Principal;
26  import java.security.PrivilegedExceptionAction;
27  
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.apache.wss4j.common.ext.WSSecurityException.ErrorCode;
30  import org.ietf.jgss.GSSContext;
31  import org.ietf.jgss.GSSCredential;
32  import org.ietf.jgss.GSSException;
33  import org.ietf.jgss.GSSManager;
34  import org.ietf.jgss.GSSName;
35  import org.ietf.jgss.Oid;
36  
37  /**
38   * This class represents a PrivilegedExceptionAction implementation to obtain a service ticket from a Kerberos
39   * Key Distribution Center.
40   */
41  public class KerberosClientExceptionAction implements PrivilegedExceptionAction<KerberosContext> {
42      private static final boolean IS_IBM_VENDOR = System.getProperty("java.vendor").startsWith("IBM");
43  
44      private static final String SUN_JGSS_INQUIRE_TYPE_CLASS = "com.sun.security.jgss.InquireType";
45      private static final String SUN_JGSS_EXT_GSSCTX_CLASS = "com.sun.security.jgss.ExtendedGSSContext";
46  
47      private static final String IBM_JGSS_INQUIRE_TYPE_CLASS = "com.ibm.security.jgss.InquireType";
48      private static final String IBM_JGSS_EXT_GSSCTX_CLASS = "com.ibm.security.jgss.ExtendedGSSContext";
49  
50      private static final String JGSS_KERBEROS_TICKET_OID = "1.2.840.113554.1.2.2";
51      private static final String JGSS_SPNEGO_TICKET_OID = "1.3.6.1.5.5.2";
52  
53      private Principal clientPrincipal;
54      private String serviceName;
55      private boolean isUsernameServiceNameForm;
56      private boolean requestCredDeleg;
57      private GSSCredential delegatedCredential;
58      private boolean spnego;
59      private boolean mutualAuth;
60  
61      public KerberosClientExceptionAction(Principal clientPrincipal, String serviceName,
62                                           boolean isUsernameServiceNameForm, boolean requestCredDeleg) {
63          this(clientPrincipal, serviceName, isUsernameServiceNameForm,
64               requestCredDeleg, null, false, false);
65      }
66  
67      public KerberosClientExceptionAction(Principal clientPrincipal, String serviceName,
68                                           boolean isUsernameServiceNameForm, boolean requestCredDeleg,
69                                           GSSCredential delegatedCredential,
70                                           boolean spnego, boolean mutualAuth) {
71          this.clientPrincipal = clientPrincipal;
72          this.serviceName = serviceName;
73          this.isUsernameServiceNameForm = isUsernameServiceNameForm;
74          this.requestCredDeleg = requestCredDeleg;
75          this.delegatedCredential = delegatedCredential;
76          this.spnego = spnego;
77          this.mutualAuth = mutualAuth;
78      }
79  
80      public KerberosContext run() throws GSSException, WSSecurityException {
81          GSSManager gssManager = GSSManager.getInstance();
82  
83          GSSName gssService = gssManager.createName(serviceName, isUsernameServiceNameForm
84                                                     ? GSSName.NT_USER_NAME : GSSName.NT_HOSTBASED_SERVICE);
85          Oid oid = null;
86          GSSCredential credentials = delegatedCredential;
87          if (spnego) {
88              oid = new Oid(JGSS_SPNEGO_TICKET_OID);
89          } else {
90              oid = new Oid(JGSS_KERBEROS_TICKET_OID);
91  
92              if (credentials == null) {
93                  GSSName gssClient = gssManager.createName(clientPrincipal.getName(), GSSName.NT_USER_NAME);
94                  credentials =
95                      gssManager.createCredential(
96                          gssClient, GSSCredential.DEFAULT_LIFETIME, oid, GSSCredential.INITIATE_ONLY
97                      );
98              }
99          }
100 
101         GSSContext secContext =
102             gssManager.createContext(
103                 gssService, oid, credentials, GSSContext.DEFAULT_LIFETIME
104             );
105 
106         secContext.requestMutualAuth(mutualAuth);
107         secContext.requestCredDeleg(requestCredDeleg);
108 
109         byte[] token = new byte[0];
110         byte[] returnedToken = secContext.initSecContext(token, 0, token.length);
111 
112         KerberosContext krbCtx = new KerberosContext();
113         krbCtx.setGssContext(secContext);
114         krbCtx.setKerberosToken(returnedToken);
115 
116         try {
117             @SuppressWarnings("rawtypes")
118             Class inquireType = Class.forName(IS_IBM_VENDOR ? IBM_JGSS_INQUIRE_TYPE_CLASS
119                 : SUN_JGSS_INQUIRE_TYPE_CLASS);
120 
121             @SuppressWarnings("rawtypes")
122             Class extendedGSSContext = Class.forName(IS_IBM_VENDOR ? IBM_JGSS_EXT_GSSCTX_CLASS
123                 : SUN_JGSS_EXT_GSSCTX_CLASS);
124 
125             @SuppressWarnings("unchecked")
126             Method inquireSecContext = extendedGSSContext.getMethod("inquireSecContext", inquireType);
127 
128             @SuppressWarnings("unchecked")
129             Key key = (Key) inquireSecContext.invoke(secContext, Enum.valueOf(inquireType, "KRB5_GET_SESSION_KEY"));
130 
131             krbCtx.setSecretKey(key);
132         } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
133             | InvocationTargetException e) {
134             throw new WSSecurityException(
135                 ErrorCode.FAILURE, e, "kerberosServiceTicketError"
136             );
137         }
138 
139         return krbCtx;
140     }
141 }