FEDIZ-196 - Add support for Apache Tomcat 8.5.x
[cxf-fediz.git] / services / idp / src / main / java / org / apache / cxf / fediz / service / idp / STSKrbAuthenticationProvider.java
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 package org.apache.cxf.fediz.service.idp;
20
21 import java.security.Principal;
22 import java.security.PrivilegedActionException;
23 import java.util.List;
24
25 import javax.security.auth.callback.CallbackHandler;
26 import javax.security.auth.login.LoginException;
27 import javax.xml.namespace.QName;
28
29 import org.apache.cxf.Bus;
30 import org.apache.cxf.fediz.service.idp.kerberos.KerberosServiceRequestToken;
31 import org.apache.cxf.fediz.service.idp.kerberos.KerberosTokenValidator;
32 import org.apache.cxf.fediz.service.idp.kerberos.PassThroughKerberosClient;
33 import org.apache.cxf.ws.security.SecurityConstants;
34 import org.apache.cxf.ws.security.tokenstore.SecurityToken;
35 import org.apache.wss4j.common.kerberos.KerberosServiceContext;
36 import org.apache.wss4j.common.principal.SAMLTokenPrincipalImpl;
37 import org.apache.wss4j.common.saml.SamlAssertionWrapper;
38 import org.apache.wss4j.dom.WSConstants;
39 import org.ietf.jgss.GSSContext;
40 import org.ietf.jgss.GSSCredential;
41 import org.ietf.jgss.GSSException;
42 import org.ietf.jgss.GSSManager;
43 import org.ietf.jgss.GSSName;
44 import org.ietf.jgss.Oid;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.security.core.Authentication;
48 import org.springframework.security.core.AuthenticationException;
49 import org.springframework.security.core.GrantedAuthority;
50
51 /**
52 * An authentication provider to authenticate a Kerberos token to the STS
53 */
54 public class STSKrbAuthenticationProvider extends STSAuthenticationProvider {
55
56 private static final Logger LOG = LoggerFactory.getLogger(STSKrbAuthenticationProvider.class);
57
58 private KerberosTokenValidator kerberosTokenValidator;
59
60 private CallbackHandler kerberosCallbackHandler;
61
62 private boolean kerberosUsernameServiceNameForm;
63
64 private boolean requireDelegation;
65
66
67 @Override
68 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
69 // We only handle KerberosServiceRequestTokens
70 if (!(authentication instanceof KerberosServiceRequestToken)) {
71 return null;
72 }
73
74 Bus cxfBus = getBus();
75 IdpSTSClient sts = new IdpSTSClient(cxfBus);
76 sts.setAddressingNamespace("http://www.w3.org/2005/08/addressing");
77 if (tokenType != null && tokenType.length() > 0) {
78 sts.setTokenType(tokenType);
79 } else {
80 sts.setTokenType(WSConstants.WSS_SAML2_TOKEN_TYPE);
81 }
82 sts.setKeyType(HTTP_DOCS_OASIS_OPEN_ORG_WS_SX_WS_TRUST_200512_BEARER);
83 sts.setWsdlLocation(wsdlLocation);
84 sts.setServiceQName(new QName(namespace, wsdlService));
85 sts.setEndpointQName(new QName(namespace, wsdlEndpoint));
86
87 sts.getProperties().putAll(properties);
88 if (use200502Namespace) {
89 sts.setNamespace(HTTP_SCHEMAS_XMLSOAP_ORG_WS_2005_02_TRUST);
90 }
91
92 if (lifetime != null) {
93 sts.setEnableLifetime(true);
94 sts.setTtl(lifetime.intValue());
95 }
96
97 return handleKerberos((KerberosServiceRequestToken)authentication, sts);
98 }
99
100 private Authentication handleKerberos(
101 KerberosServiceRequestToken kerberosRequestToken,
102 IdpSTSClient sts
103 ) {
104 Principal kerberosPrincipal = null;
105 //
106 // If delegation is required then validate the received token + store the
107 // Delegated Credential so that we can retrieve a new kerberos token for the
108 // STS with it. If delegation is not required, then we just get the received
109 // token + pass it to the STS
110 //
111 if (requireDelegation) {
112 kerberosPrincipal = validateKerberosToken(kerberosRequestToken, sts);
113 if (kerberosPrincipal == null) {
114 return null;
115 }
116 } else {
117 PassThroughKerberosClient kerberosClient = new PassThroughKerberosClient();
118 kerberosClient.setToken(kerberosRequestToken.getToken());
119 sts.getProperties().put(SecurityConstants.KERBEROS_CLIENT, kerberosClient);
120 }
121
122 try {
123 // Line below may be uncommented for debugging
124 // setTimeout(sts.getClient(), 3600000L);
125
126 SecurityToken token = sts.requestSecurityToken(this.appliesTo);
127
128 if (kerberosPrincipal == null && token.getToken() != null
129 && "Assertion".equals(token.getToken().getLocalName())) {
130 // For the pass-through Kerberos case, we don't know the Principal name...
131 kerberosPrincipal =
132 new SAMLTokenPrincipalImpl(new SamlAssertionWrapper(token.getToken()));
133 }
134
135 List<GrantedAuthority> authorities = createAuthorities(token);
136
137 KerberosServiceRequestToken ksrt =
138 new KerberosServiceRequestToken(kerberosPrincipal, authorities, kerberosRequestToken.getToken());
139
140 STSUserDetails details = new STSUserDetails(kerberosPrincipal.getName(),
141 "",
142 authorities,
143 token);
144 ksrt.setDetails(details);
145
146 LOG.debug("[IDP_TOKEN={}] provided for user '{}'", token.getId(), kerberosPrincipal.getName());
147 return ksrt;
148 } catch (Exception ex) {
149 LOG.info("Failed to authenticate user '" + kerberosRequestToken.getName() + "'", ex);
150 return null;
151 }
152 }
153
154 private Principal validateKerberosToken(
155 KerberosServiceRequestToken token,
156 IdpSTSClient sts
157 ) {
158 if (kerberosTokenValidator == null) {
159 LOG.error("KerberosTokenValidator must be configured to support kerberos "
160 + "credential delegation");
161 return null;
162 }
163 KerberosServiceContext kerberosContext;
164 Principal kerberosPrincipal = null;
165 try {
166 kerberosContext = kerberosTokenValidator.validate(token);
167 if (kerberosContext == null || kerberosContext.getDelegationCredential() == null) {
168 LOG.info("Kerberos Validation failure");
169 return null;
170 }
171 GSSCredential delegatedCredential = kerberosContext.getDelegationCredential();
172 sts.getProperties().put(SecurityConstants.DELEGATED_CREDENTIAL,
173 delegatedCredential);
174 sts.getProperties().put(SecurityConstants.KERBEROS_USE_CREDENTIAL_DELEGATION, "true");
175 kerberosPrincipal = kerberosContext.getPrincipal();
176 } catch (LoginException ex) {
177 LOG.info("Failed to authenticate user", ex);
178 return null;
179 } catch (PrivilegedActionException ex) {
180 LOG.info("Failed to authenticate user", ex);
181 return null;
182 }
183
184 if (kerberosTokenValidator.getContextName() != null) {
185 sts.getProperties().put(SecurityConstants.KERBEROS_JAAS_CONTEXT_NAME,
186 kerberosTokenValidator.getContextName());
187 }
188 if (kerberosTokenValidator.getServiceName() != null) {
189 sts.getProperties().put(SecurityConstants.KERBEROS_SPN,
190 kerberosTokenValidator.getServiceName());
191 }
192 if (kerberosCallbackHandler != null) {
193 sts.getProperties().put(SecurityConstants.CALLBACK_HANDLER,
194 kerberosCallbackHandler);
195 }
196 if (kerberosUsernameServiceNameForm) {
197 sts.getProperties().put(SecurityConstants.KERBEROS_IS_USERNAME_IN_SERVICENAME_FORM,
198 "true");
199 }
200
201 return kerberosPrincipal;
202 }
203
204 protected GSSContext createGSSContext() throws GSSException {
205 Oid oid = new Oid("1.2.840.113554.1.2.2");
206
207 GSSManager gssManager = GSSManager.getInstance();
208
209 String spn = "bob@service.ws.apache.org";
210 GSSName gssService = gssManager.createName(spn, null);
211
212 return gssManager.createContext(gssService.canonicalize(oid),
213 oid, null, GSSContext.DEFAULT_LIFETIME);
214
215 }
216
217 @Override
218 public boolean supports(Class<?> authentication) {
219 return authentication.equals(KerberosServiceRequestToken.class);
220 }
221
222 public KerberosTokenValidator getKerberosTokenValidator() {
223 return kerberosTokenValidator;
224 }
225
226 public void setKerberosTokenValidator(KerberosTokenValidator kerberosTokenValidator) {
227 this.kerberosTokenValidator = kerberosTokenValidator;
228 }
229
230 public CallbackHandler getKerberosCallbackHandler() {
231 return kerberosCallbackHandler;
232 }
233
234 public void setKerberosCallbackHandler(CallbackHandler kerberosCallbackHandler) {
235 this.kerberosCallbackHandler = kerberosCallbackHandler;
236 }
237
238 public boolean isKerberosUsernameServiceNameForm() {
239 return kerberosUsernameServiceNameForm;
240 }
241
242 public void setKerberosUsernameServiceNameForm(boolean kerberosUsernameServiceNameForm) {
243 this.kerberosUsernameServiceNameForm = kerberosUsernameServiceNameForm;
244 }
245
246 public boolean isRequireDelegation() {
247 return requireDelegation;
248 }
249
250 public void setRequireDelegation(boolean requireDelegation) {
251 this.requireDelegation = requireDelegation;
252 }
253
254 }