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.validate;
21
22 import java.security.Key;
23 import java.security.Principal;
24 import java.security.PrivilegedActionException;
25 import java.util.Set;
26
27 import javax.security.auth.Subject;
28 import javax.security.auth.callback.CallbackHandler;
29 import javax.security.auth.login.LoginContext;
30 import javax.security.auth.login.LoginException;
31
32 import org.apache.wss4j.common.ext.WSSecurityException;
33 import org.apache.wss4j.common.ext.WSSecurityException.ErrorCode;
34 import org.apache.wss4j.common.kerberos.KerberosServiceContext;
35 import org.apache.wss4j.common.kerberos.KerberosServiceExceptionAction;
36 import org.apache.wss4j.common.kerberos.KerberosTokenDecoder;
37 import org.apache.wss4j.common.kerberos.KerberosTokenDecoderException;
38 import org.apache.wss4j.common.token.BinarySecurity;
39 import org.apache.wss4j.dom.handler.RequestData;
40 import org.apache.wss4j.dom.message.token.KerberosSecurity;
41
42
43
44 public class KerberosTokenValidator implements Validator {
45
46 private static final org.slf4j.Logger LOG =
47 org.slf4j.LoggerFactory.getLogger(KerberosTokenValidator.class);
48
49 private String serviceName;
50 private CallbackHandler callbackHandler;
51 private String contextName;
52 private KerberosTokenDecoder kerberosTokenDecoder;
53 private boolean isUsernameServiceNameForm;
54 private boolean spnego;
55
56
57
58
59
60 public String getContextName() {
61 return contextName;
62 }
63
64
65
66
67
68 public void setContextName(String contextName) {
69 this.contextName = contextName;
70 }
71
72
73
74
75
76 public CallbackHandler getCallbackHandler() {
77 return callbackHandler;
78 }
79
80
81
82
83
84 public void setCallbackHandler(CallbackHandler callbackHandler) {
85 this.callbackHandler = callbackHandler;
86 }
87
88
89
90
91
92
93 public void setServiceName(String serviceName) {
94 this.serviceName = serviceName;
95 }
96
97
98
99
100
101
102 public String getServiceName() {
103 return serviceName;
104 }
105
106
107
108
109
110
111 public KerberosTokenDecoder getKerberosTokenDecoder() {
112 return kerberosTokenDecoder;
113 }
114
115
116
117
118
119
120 public void setKerberosTokenDecoder(KerberosTokenDecoder kerberosTokenDecoder) {
121 this.kerberosTokenDecoder = kerberosTokenDecoder;
122 }
123
124
125
126
127
128
129
130
131 public Credential validate(Credential credential, RequestData data) throws WSSecurityException {
132 if (credential == null || credential.getBinarySecurityToken() == null) {
133 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCredential");
134 }
135
136 BinarySecurity binarySecurity = credential.getBinarySecurityToken();
137 if (!(binarySecurity instanceof KerberosSecurity)) {
138 return credential;
139 }
140
141 if (LOG.isDebugEnabled()) {
142 try {
143 String jaasAuth = System.getProperty("java.security.auth.login.config");
144 String krbConf = System.getProperty("java.security.krb5.conf");
145 LOG.debug("KerberosTokenValidator - Using JAAS auth login file: " + jaasAuth);
146 LOG.debug("KerberosTokenValidator - Using KRB conf file: " + krbConf);
147 } catch (SecurityException ex) {
148 LOG.debug(ex.getMessage(), ex);
149 }
150 }
151
152
153 LoginContext loginContext = null;
154 try {
155 if (callbackHandler != null) {
156 loginContext = new LoginContext(getContextName(), callbackHandler);
157 } else if (data.getCallbackHandler() != null) {
158 loginContext = new LoginContext(getContextName(), data.getCallbackHandler());
159 } else {
160 loginContext = new LoginContext(getContextName());
161 }
162 loginContext.login();
163 } catch (LoginException ex) {
164 LOG.debug(ex.getMessage(), ex);
165 throw new WSSecurityException(
166 WSSecurityException.ErrorCode.FAILURE, ex,
167 "kerberosLoginError",
168 new Object[] {ex.getMessage()}
169 );
170 }
171 LOG.debug("Successfully authenticated to the TGT");
172
173 byte[] token = binarySecurity.getToken();
174
175
176 Subject subject = loginContext.getSubject();
177 String service = serviceName;
178 if (service == null) {
179 Set<Principal> principals = subject.getPrincipals();
180 if (principals.isEmpty()) {
181 throw new WSSecurityException(
182 WSSecurityException.ErrorCode.FAILURE,
183 "kerberosLoginError",
184 new Object[] {"No Client principals found after login"});
185 }
186 service = principals.iterator().next().getName();
187 }
188
189
190 KerberosServiceExceptionAction action =
191 new KerberosServiceExceptionAction(token, service,
192 isUsernameServiceNameForm(), spnego);
193 KerberosServiceContext krbServiceCtx = null;
194 try {
195 krbServiceCtx = Subject.doAs(subject, action);
196 } catch (PrivilegedActionException e) {
197 Throwable cause = e.getCause();
198 if (cause instanceof WSSecurityException) {
199 throw (WSSecurityException) cause;
200 } else {
201 throw new WSSecurityException(
202 ErrorCode.FAILURE, new Exception(cause), "kerberosTicketValidationError"
203 );
204 }
205 }
206
207 credential.setPrincipal(krbServiceCtx.getPrincipal());
208 credential.setDelegationCredential(krbServiceCtx.getDelegationCredential());
209
210
211 LOG.debug("Trying to obtain the Session Key from the KerberosServiceContext.");
212 Key sessionKey = krbServiceCtx.getSessionKey();
213 if (null != sessionKey) {
214 LOG.debug("Found session key in the KerberosServiceContext.");
215 credential.setSecretKey(sessionKey.getEncoded());
216 } else {
217 LOG.debug("Session key is not found in the KerberosServiceContext.");
218 }
219
220
221
222 if (null == credential.getSecretKey() && kerberosTokenDecoder != null) {
223 LOG.debug("KerberosTokenDecoder is set.Trying to obtain the session key from it.");
224 kerberosTokenDecoder.clear();
225 kerberosTokenDecoder.setToken(token);
226 kerberosTokenDecoder.setSubject(subject);
227 try {
228 byte[] key = kerberosTokenDecoder.getSessionKey();
229 if (null != key) {
230 LOG.debug("Session key obtained from the KerberosTokenDecoder.");
231 credential.setSecretKey(key);
232 } else {
233 LOG.debug("Session key could not be obtained from the KerberosTokenDecoder.");
234 }
235 } catch (KerberosTokenDecoderException e) {
236
237 throw new WSSecurityException(ErrorCode.FAILURE, e, "Error retrieving session key.");
238 }
239 } else {
240 LOG.debug("KerberosTokenDecoder is not set.");
241 }
242
243 LOG.debug("Successfully validated a ticket");
244
245 return credential;
246 }
247
248
249
250
251
252
253
254
255
256
257 public boolean isUsernameServiceNameForm() {
258 return isUsernameServiceNameForm;
259 }
260
261
262
263
264
265
266
267
268
269 public void setUsernameServiceNameForm(boolean isUsernameServiceNameForm) {
270 this.isUsernameServiceNameForm = isUsernameServiceNameForm;
271 }
272
273 public boolean isSpnego() {
274 return spnego;
275 }
276
277 public void setSpnego(boolean spnego) {
278 this.spnego = spnego;
279 }
280 }