1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.message.token;
21
22 import java.io.IOException;
23 import java.security.Key;
24 import java.security.Principal;
25 import java.security.PrivilegedActionException;
26 import java.util.Set;
27
28 import javax.crypto.SecretKey;
29 import javax.crypto.spec.SecretKeySpec;
30 import javax.security.auth.Subject;
31 import javax.security.auth.callback.Callback;
32 import javax.security.auth.callback.CallbackHandler;
33 import javax.security.auth.callback.UnsupportedCallbackException;
34 import javax.security.auth.kerberos.KerberosTicket;
35 import javax.security.auth.login.LoginContext;
36 import javax.security.auth.login.LoginException;
37
38 import org.apache.wss4j.common.bsp.BSPEnforcer;
39 import org.apache.wss4j.common.bsp.BSPRule;
40 import org.apache.wss4j.common.ext.WSSecurityException;
41 import org.apache.wss4j.common.ext.WSSecurityException.ErrorCode;
42 import org.apache.wss4j.common.kerberos.KerberosClientExceptionAction;
43 import org.apache.wss4j.common.kerberos.KerberosContext;
44 import org.apache.wss4j.common.kerberos.KerberosContextAndServiceNameCallback;
45 import org.apache.wss4j.common.token.BinarySecurity;
46 import org.apache.wss4j.dom.WSConstants;
47 import org.ietf.jgss.GSSCredential;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.Element;
50
51
52
53
54 public class KerberosSecurity extends BinarySecurity {
55
56 private static final org.slf4j.Logger LOG =
57 org.slf4j.LoggerFactory.getLogger(KerberosSecurity.class);
58 private SecretKey secretKey;
59
60
61
62
63
64
65
66
67
68 public KerberosSecurity(Element elem, BSPEnforcer bspEnforcer) throws WSSecurityException {
69 super(elem, bspEnforcer);
70 String valueType = getValueType();
71 if (!WSConstants.WSS_GSS_KRB_V5_AP_REQ.equals(valueType)) {
72 bspEnforcer.handleBSPRule(BSPRule.R6902);
73 }
74 }
75
76
77
78
79
80
81 public KerberosSecurity(Document doc) {
82 super(doc);
83 }
84
85
86
87
88 public boolean isV5ApReq() {
89 String type = getValueType();
90 return WSConstants.WSS_KRB_V5_AP_REQ.equals(type)
91 || WSConstants.WSS_KRB_V5_AP_REQ1510.equals(type)
92 || WSConstants.WSS_KRB_V5_AP_REQ4120.equals(type);
93 }
94
95
96
97
98 public boolean isGssV5ApReq() {
99 String type = getValueType();
100 return WSConstants.WSS_GSS_KRB_V5_AP_REQ.equals(type)
101 || WSConstants.WSS_GSS_KRB_V5_AP_REQ1510.equals(type)
102 || WSConstants.WSS_GSS_KRB_V5_AP_REQ4120.equals(type);
103 }
104
105
106
107
108
109
110
111
112 public void retrieveServiceTicket(
113 CallbackHandler callbackHandler
114 ) throws WSSecurityException {
115 KerberosContextAndServiceNameCallback contextAndServiceNameCallback =
116 new KerberosContextAndServiceNameCallback();
117 try {
118 callbackHandler.handle(new Callback[]{contextAndServiceNameCallback});
119 } catch (IOException | UnsupportedCallbackException e) {
120 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
121 }
122
123 String jaasLoginModuleName = contextAndServiceNameCallback.getContextName();
124 if (jaasLoginModuleName == null) {
125 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
126 "kerberosCallbackContextNameNotSupplied");
127 }
128 String serviceName = contextAndServiceNameCallback.getServiceName();
129 if (serviceName == null) {
130 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
131 "kerberosCallbackServiceNameNotSupplied");
132 }
133
134 retrieveServiceTicket(jaasLoginModuleName, callbackHandler, serviceName);
135 }
136
137
138
139
140
141
142
143
144
145 public void retrieveServiceTicket(
146 String jaasLoginModuleName,
147 CallbackHandler callbackHandler,
148 String serviceName
149 ) throws WSSecurityException {
150 retrieveServiceTicket(jaasLoginModuleName, callbackHandler, serviceName, false);
151 }
152
153 public void retrieveServiceTicket(
154 String jaasLoginModuleName,
155 CallbackHandler callbackHandler,
156 String serviceName,
157 boolean isUsernameServiceNameForm
158 ) throws WSSecurityException {
159 retrieveServiceTicket(jaasLoginModuleName, callbackHandler, serviceName,
160 isUsernameServiceNameForm, false);
161 }
162
163 public void retrieveServiceTicket(
164 String jaasLoginModuleName,
165 CallbackHandler callbackHandler,
166 String serviceName,
167 boolean isUsernameServiceNameForm,
168 boolean requestCredDeleg
169 ) throws WSSecurityException {
170 retrieveServiceTicket(jaasLoginModuleName, callbackHandler, serviceName,
171 isUsernameServiceNameForm, requestCredDeleg, null);
172 }
173
174 public void retrieveServiceTicket(
175 String jaasLoginModuleName,
176 CallbackHandler callbackHandler,
177 String serviceName,
178 boolean isUsernameServiceNameForm,
179 boolean requestCredDeleg,
180 GSSCredential delegatedCredential
181 ) throws WSSecurityException {
182
183 LoginContext loginContext = null;
184 try {
185 if (callbackHandler == null) {
186 loginContext = new LoginContext(jaasLoginModuleName);
187 } else {
188 loginContext = new LoginContext(jaasLoginModuleName, callbackHandler);
189 }
190 loginContext.login();
191 } catch (LoginException ex) {
192 LOG.debug(ex.getMessage(), ex);
193 throw new WSSecurityException(
194 WSSecurityException.ErrorCode.FAILURE, ex,
195 "kerberosLoginError",
196 new Object[] {ex.getMessage()}
197 );
198 }
199 LOG.debug("Successfully authenticated to the TGT");
200
201 Subject clientSubject = loginContext.getSubject();
202 Set<Principal> clientPrincipals = clientSubject.getPrincipals();
203 if (clientPrincipals.isEmpty()) {
204 throw new WSSecurityException(
205 WSSecurityException.ErrorCode.FAILURE,
206 "kerberosLoginError",
207 new Object[] {"No Client principals found after login"});
208 }
209
210 KerberosTicket tgt = getKerberosTicket(clientSubject, null);
211
212 decorateSubject(clientSubject);
213
214
215 KerberosClientExceptionAction action =
216 new KerberosClientExceptionAction(clientPrincipals.iterator().next(), serviceName,
217 isUsernameServiceNameForm, requestCredDeleg,
218 delegatedCredential, false, false);
219 KerberosContext krbCtx = null;
220 try {
221 krbCtx = Subject.doAs(clientSubject, action);
222
223
224 Key sessionKey = krbCtx.getSecretKey();
225 if (sessionKey != null) {
226 secretKey = new SecretKeySpec(sessionKey.getEncoded(), sessionKey.getAlgorithm());
227 } else {
228 KerberosTicket serviceTicket = getKerberosTicket(clientSubject, tgt);
229 if (serviceTicket != null) {
230 secretKey = serviceTicket.getSessionKey();
231 }
232 }
233
234 if (secretKey == null) {
235 LOG.debug("No secret key for kerberos was found");
236 } else {
237 LOG.debug("Successfully retrieved a secret key for kerberos");
238 }
239
240 setToken(krbCtx.getKerberosToken());
241 } catch (PrivilegedActionException e) {
242 Throwable cause = e.getCause();
243 if (cause instanceof WSSecurityException) {
244 throw (WSSecurityException) cause;
245 } else {
246 throw new WSSecurityException(
247 ErrorCode.FAILURE, new Exception(cause), "kerberosServiceTicketError"
248 );
249 }
250 } finally {
251 if (krbCtx != null) {
252 krbCtx.dispose();
253 }
254 }
255 LOG.debug("Successfully retrieved a service ticket");
256
257 if (getValueType().length() == 0) {
258 setValueType(WSConstants.WSS_GSS_KRB_V5_AP_REQ);
259 }
260 }
261
262
263 protected void decorateSubject(Subject subject) {
264
265 }
266
267
268
269
270
271 private KerberosTicket getKerberosTicket(Subject clientSubject, KerberosTicket previousTicket) {
272 Set<KerberosTicket> privateCredentials = clientSubject.getPrivateCredentials(KerberosTicket.class);
273 if (privateCredentials == null || privateCredentials.isEmpty()) {
274 LOG.debug("Kerberos client subject private credentials are null");
275 return null;
276 }
277
278 for (KerberosTicket privateCredential : privateCredentials) {
279 if (!privateCredential.equals(previousTicket)) {
280 return privateCredential;
281 }
282 }
283 return null;
284 }
285
286
287
288
289
290 public SecretKey getSecretKey() {
291 return secretKey;
292 }
293
294
295
296
297
298
299 public static boolean isKerberosToken(String valueType) {
300 return WSConstants.WSS_KRB_V5_AP_REQ.equals(valueType)
301 || WSConstants.WSS_GSS_KRB_V5_AP_REQ.equals(valueType)
302 || WSConstants.WSS_KRB_V5_AP_REQ1510.equals(valueType)
303 || WSConstants.WSS_GSS_KRB_V5_AP_REQ1510.equals(valueType)
304 || WSConstants.WSS_KRB_V5_AP_REQ4120.equals(valueType)
305 || WSConstants.WSS_GSS_KRB_V5_AP_REQ4120.equals(valueType);
306 }
307
308 @Override
309 public boolean equals(Object object) {
310 if (!(object instanceof KerberosSecurity)) {
311 return false;
312 }
313
314 KerberosSecurity that = (KerberosSecurity)object;
315 if (secretKey != null && !secretKey.equals(that.secretKey)) {
316 return false;
317 } else if (secretKey == null && that.secretKey != null) {
318 return false;
319 }
320
321 return super.equals(object);
322 }
323
324 @Override
325 public int hashCode() {
326 int hashCode = 17;
327 if (secretKey != null) {
328 hashCode *= 31 + secretKey.hashCode();
329 }
330 hashCode *= 31 + super.hashCode();
331
332 return hashCode;
333 }
334 }