You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2012/07/18 00:14:36 UTC
svn commit: r1362686 - in /cxf/trunk:
api/src/main/java/org/apache/cxf/common/security/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/
rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/
systests/jaxrs/src/test/java/org...
Author: sergeyb
Date: Tue Jul 17 22:14:35 2012
New Revision: 1362686
URL: http://svn.apache.org/viewvc?rev=1362686&view=rev
Log:
[CXF-4430] SpnegoAuthSupplier updates, also adding Kerberos interceptor and filter
Added:
cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java (with props)
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java (with props)
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java (with props)
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java (with props)
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java (with props)
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java (with props)
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberos.cfg
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml (with props)
Modified:
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/SpnegoAuthSupplier.java
Added: cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java (added)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.common.security;
+
+import java.security.Principal;
+
+import org.apache.cxf.security.SecurityContext;
+
+public class SimpleSecurityContext implements SecurityContext {
+ private SimplePrincipal principal;
+ public SimpleSecurityContext(String name) {
+ this.principal = new SimplePrincipal(name);
+ }
+
+ public Principal getUserPrincipal() {
+ return principal;
+ }
+
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+}
Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/common/security/SimpleSecurityContext.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.security;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.configuration.security.AuthorizationPolicy;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.phase.PhaseInterceptor;
+import org.apache.cxf.transport.http.auth.AbstractSpnegoAuthSupplier;
+
+public class KerberosAuthOutInterceptor extends AbstractSpnegoAuthSupplier
+ implements PhaseInterceptor<Message> {
+
+ private String phase = Phase.MARSHAL;
+ private AuthorizationPolicy policy;
+
+ public KerberosAuthOutInterceptor() {
+
+ }
+ public KerberosAuthOutInterceptor(String phase) {
+ this.phase = phase;
+ }
+
+ public void handleMessage(Message message) throws Fault {
+ URL currentURL = getCurrentURL(message);
+ String value = super.getAuthorization(getPolicy(),
+ currentURL,
+ message);
+ Map<String, List<String>> headers =
+ CastUtils.cast((Map<?, ?>)message.get(Message.PROTOCOL_HEADERS));
+ if (headers == null) {
+ headers = new HashMap<String, List<String>>();
+ message.put(Message.PROTOCOL_HEADERS, headers);
+ }
+ headers.put("Authorization", Collections.singletonList(value));
+ }
+
+ private URL getCurrentURL(Message message) {
+ try {
+ return new URL((String)message.get(Message.ENDPOINT_ADDRESS));
+ } catch (MalformedURLException ex) {
+ // is not expected to happen
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public void handleFault(Message message) {
+ // complete
+ }
+
+ public Set<String> getAfter() {
+ return Collections.emptySet();
+ }
+
+ public Set<String> getBefore() {
+ return Collections.emptySet();
+ }
+
+ public String getId() {
+ return getClass().getName();
+ }
+
+ public String getPhase() {
+ return phase;
+ }
+
+ public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() {
+ return Collections.emptySet();
+ }
+ public AuthorizationPolicy getPolicy() {
+ return policy;
+ }
+ public void setPolicy(AuthorizationPolicy policy) {
+ this.policy = policy;
+ }
+
+}
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthOutInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,183 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.jaxrs.security;
+
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.List;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.common.security.SimpleSecurityContext;
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.ext.RequestHandler;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.security.SecurityContext;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+public class KerberosAuthenticationFilter implements RequestHandler {
+
+ private static final String NEGOTIATE_SCHEME = "Negotiate";
+ private static final String PROPERTY_USE_KERBEROS_OID = "auth.spnego.useKerberosOid";
+ private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
+ private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+
+ private MessageContext messageContext;
+ private CallbackHandler callbackHandler;
+ private String loginContextName;
+ private String servicePrincipalName;
+ private String realm;
+
+ public Response handleRequest(Message m, ClassResourceInfo resourceClass) {
+
+ List<String> authHeaders = messageContext.getHttpHeaders()
+ .getRequestHeader(HttpHeaders.AUTHORIZATION);
+ if (authHeaders.size() != 1) {
+ throw new WebApplicationException(getFaultResponse());
+ }
+ String[] authPair = authHeaders.get(0).split(" ");
+ if (authPair.length != 2 || !NEGOTIATE_SCHEME.equalsIgnoreCase(authPair[0])) {
+ throw new WebApplicationException(getFaultResponse());
+ }
+
+ byte[] serviceTicket = getServiceTicket(authPair[1]);
+
+ try {
+ Subject serviceSubject = loginAndGetSubject();
+
+ GSSContext gssContext = createGSSContext();
+
+ Subject.doAs(serviceSubject, new ValidateServiceTicketAction(gssContext, serviceTicket));
+
+ final String clientName = gssContext.getSrcName().toString();
+ m.put(SecurityContext.class, new SimpleSecurityContext(clientName));
+
+ } catch (LoginException e) {
+ throw new WebApplicationException(getFaultResponse());
+ } catch (GSSException e) {
+ throw new WebApplicationException(getFaultResponse());
+ } catch (PrivilegedActionException e) {
+ throw new WebApplicationException(getFaultResponse());
+ }
+
+ return null;
+ }
+
+ protected GSSContext createGSSContext() throws GSSException {
+ boolean useKerberosOid = MessageUtils.isTrue(
+ messageContext.getContextualProperty(PROPERTY_USE_KERBEROS_OID));
+ Oid oid = new Oid(useKerberosOid ? KERBEROS_OID : SPNEGO_OID);
+
+ GSSManager gssManager = GSSManager.getInstance();
+
+ String spn = getCompleteServicePrincipalName();
+ GSSName gssService = gssManager.createName(spn, null);
+
+ return gssManager.createContext(gssService.canonicalize(oid),
+ oid, null, GSSContext.DEFAULT_LIFETIME);
+ }
+
+ protected Subject loginAndGetSubject() throws LoginException {
+
+ // The login without a callback can work if
+ // - Kerberos keytabs are used with a principal name set in the JAAS config
+ // - TGT cache is available and either a principalName is set in the JAAS config
+ // or Kerberos is integrated into the OS logon process
+ // meaning that a process which runs this code has the
+ // user identity
+
+ LoginContext lc = callbackHandler != null
+ ? new LoginContext(loginContextName, callbackHandler) : new LoginContext(loginContextName);
+ lc.login();
+ return lc.getSubject();
+ }
+
+ private byte[] getServiceTicket(String encodedServiceTicket) {
+ try {
+ return Base64Utility.decode(encodedServiceTicket);
+ } catch (Base64Exception ex) {
+ throw new WebApplicationException(getFaultResponse());
+ }
+ }
+
+ private static Response getFaultResponse() {
+ return Response.status(401).header(HttpHeaders.WWW_AUTHENTICATE, NEGOTIATE_SCHEME).build();
+ }
+
+ protected String getCompleteServicePrincipalName() {
+ String name = servicePrincipalName == null
+ ? "HTTP/" + messageContext.getUriInfo().getBaseUri().getHost() : servicePrincipalName;
+ if (realm != null) {
+ name += "@" + realm;
+ }
+ return name;
+
+
+ }
+
+ @Context
+ public void setMessageContext(MessageContext context) {
+ this.messageContext = context;
+ }
+
+ public void setLoginContextName(String contextName) {
+ this.loginContextName = contextName;
+ }
+
+ public void setServicePrincipalName(String servicePrincipalName) {
+ this.servicePrincipalName = servicePrincipalName;
+ }
+
+ public void setRealm(String realm) {
+ this.realm = realm;
+ }
+
+ public void setCallbackHandler(CallbackHandler callbackHandler) {
+ this.callbackHandler = callbackHandler;
+ }
+
+ private final class ValidateServiceTicketAction implements PrivilegedExceptionAction<byte[]> {
+ private final GSSContext context;
+ private final byte[] token;
+
+ private ValidateServiceTicketAction(GSSContext context, byte[] token) {
+ this.context = context;
+ this.token = token;
+ }
+
+ public byte[] run() throws GSSException {
+ return context.acceptSecContext(token, 0, token.length);
+ }
+ }
+}
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/security/KerberosAuthenticationFilter.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java (added)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,208 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.transport.http.auth;
+
+import java.net.URL;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.configuration.security.AuthorizationPolicy;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+public abstract class AbstractSpnegoAuthSupplier {
+ protected static final Logger LOG = LogUtils.getL7dLogger(AbstractSpnegoAuthSupplier.class);
+
+ /**
+ * Can be set on the client properties. If set to true then the kerberos oid is used
+ * instead of the default spnego OID
+ */
+ private static final String PROPERTY_USE_KERBEROS_OID = "auth.spnego.useKerberosOid";
+ private static final String PROPERTY_REQUIRE_MUTUAL_AUTH = "auth.spnego.requireMutualAuth";
+ private static final String PROPERTY_REQUIRE_CRED_DELEGATION = "auth.spnego.requireCredDelegation";
+
+ private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
+ private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+
+ private String servicePrincipalName;
+ private String realm;
+ private boolean mutualAuth;
+ private boolean credDelegation;
+
+
+ public String getAuthorization(AuthorizationPolicy authPolicy,
+ URL currentURL,
+ Message message) {
+ if (!HttpAuthHeader.AUTH_TYPE_NEGOTIATE.equals(authPolicy.getAuthorizationType())) {
+ return null;
+ }
+ try {
+ String spn = getCompleteServicePrincipalName(currentURL);
+
+ boolean useKerberosOid = MessageUtils.isTrue(
+ message.getContextualProperty(PROPERTY_USE_KERBEROS_OID));
+ Oid oid = new Oid(useKerberosOid ? KERBEROS_OID : SPNEGO_OID);
+
+ byte[] token = getToken(authPolicy, spn, oid, message);
+ return HttpAuthHeader.AUTH_TYPE_NEGOTIATE + " " + Base64Utility.encode(token);
+ } catch (LoginException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } catch (GSSException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Create and return service ticket token
+ *
+ * @param authPolicy
+ * @param context
+ * @return
+ * @throws GSSException
+ * @throws LoginException
+ */
+ private byte[] getToken(AuthorizationPolicy authPolicy,
+ final GSSContext context) throws GSSException,
+ LoginException {
+ final byte[] token = new byte[0];
+
+ if (authPolicy.getUserName() == null || authPolicy.getUserName().trim().length() == 0) {
+ return context.initSecContext(token, 0, token.length);
+ }
+
+ LoginContext lc = new LoginContext(authPolicy.getAuthorization(), getUsernamePasswordHandler(
+ authPolicy.getUserName(), authPolicy.getPassword()));
+ lc.login();
+
+ try {
+ return (byte[])Subject.doAs(lc.getSubject(), new CreateServiceTicketAction(context, token));
+ } catch (PrivilegedActionException e) {
+ if (e.getCause() instanceof GSSException) {
+ throw (GSSException) e.getCause();
+ }
+ LOG.log(Level.SEVERE, "initSecContext", e);
+ return null;
+ }
+ }
+
+ /**
+ * Create and return a service ticket token for a given service principal
+ * name
+ *
+ * @param authPolicy
+ * @param spn
+ * @return service ticket token
+ * @throws GSSException
+ * @throws LoginException
+ */
+ private byte[] getToken(AuthorizationPolicy authPolicy,
+ String spn,
+ Oid oid,
+ Message message) throws GSSException,
+ LoginException {
+ GSSManager manager = GSSManager.getInstance();
+ GSSName serverName = manager.createName(spn, null);
+
+ GSSContext context = manager
+ .createContext(serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
+ context.requestMutualAuth(isMutualAuthRequired(message));
+ context.requestCredDeleg(isCredDelegationRequired(message));
+
+ return getToken(authPolicy, context);
+ }
+
+ protected boolean isMutualAuthRequired(Message message) {
+ Object prop = message.getContextualProperty(PROPERTY_REQUIRE_MUTUAL_AUTH);
+ return prop == null ? mutualAuth : MessageUtils.isTrue(prop);
+ }
+
+ protected boolean isCredDelegationRequired(Message message) {
+ Object prop = message.getContextualProperty(PROPERTY_REQUIRE_CRED_DELEGATION);
+ return prop == null ? credDelegation : MessageUtils.isTrue(prop);
+ }
+
+ protected String getCompleteServicePrincipalName(URL currentURL) {
+ String name = servicePrincipalName == null
+ ? "HTTP/" + currentURL.getHost() : servicePrincipalName;
+ if (realm != null) {
+ name += "@" + realm;
+ }
+ return name;
+
+
+ }
+
+ public void setServicePrincipalName(String servicePrincipalName) {
+ this.servicePrincipalName = servicePrincipalName;
+ }
+
+ public void setRealm(String realm) {
+ this.realm = realm;
+ }
+
+ private final class CreateServiceTicketAction implements PrivilegedExceptionAction<byte[]> {
+ private final GSSContext context;
+ private final byte[] token;
+
+ private CreateServiceTicketAction(GSSContext context, byte[] token) {
+ this.context = context;
+ this.token = token;
+ }
+
+ public byte[] run() throws GSSException {
+ return context.initSecContext(token, 0, token.length);
+ }
+ }
+
+ public static CallbackHandler getUsernamePasswordHandler(final String username, final String password) {
+ final CallbackHandler handler = new CallbackHandler() {
+
+ public void handle(final Callback[] callback) {
+ for (int i = 0; i < callback.length; i++) {
+ if (callback[i] instanceof NameCallback) {
+ final NameCallback nameCallback = (NameCallback) callback[i];
+ nameCallback.setName(username);
+ } else if (callback[i] instanceof PasswordCallback) {
+ final PasswordCallback passCallback = (PasswordCallback) callback[i];
+ passCallback.setPassword(password.toCharArray());
+ }
+ }
+ }
+ };
+ return handler;
+ }
+
+}
Propchange: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/AbstractSpnegoAuthSupplier.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/SpnegoAuthSupplier.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/SpnegoAuthSupplier.java?rev=1362686&r1=1362685&r2=1362686&view=diff
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/SpnegoAuthSupplier.java (original)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/auth/SpnegoAuthSupplier.java Tue Jul 17 22:14:35 2012
@@ -19,42 +19,13 @@
package org.apache.cxf.transport.http.auth;
import java.net.URL;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.common.util.Base64Utility;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.message.Message;
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.GSSName;
-import org.ietf.jgss.Oid;
-
-public class SpnegoAuthSupplier implements HttpAuthSupplier {
- /**
- * Can be set on the jaxws:properties. If set to true then the kerberos oid is used
- * instead of the default spnego OID
- */
- private static final String PROPERTY_USE_KERBEROS_OID = "auth.spnego.useKerberosOid";
- private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
- private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
- private static final Logger LOG = LogUtils.getL7dLogger(SpnegoAuthSupplier.class);
+public class SpnegoAuthSupplier extends AbstractSpnegoAuthSupplier
+ implements HttpAuthSupplier {
- private LoginContext lc;
-
public boolean requiresRequestCaching() {
return false;
}
@@ -63,117 +34,7 @@ public class SpnegoAuthSupplier implemen
URL currentURL,
Message message,
String fullHeader) {
- if (!HttpAuthHeader.AUTH_TYPE_NEGOTIATE.equals(authPolicy.getAuthorizationType())) {
- return null;
- }
- try {
- String spn = "HTTP/" + currentURL.getHost();
- LOG.fine("Adding authorization service ticket for service principal name: " + spn);
-
- String userKerbOidSt = (String)message.getContextualProperty(PROPERTY_USE_KERBEROS_OID);
- boolean useKerberosOid = "true".equals(userKerbOidSt);
- Oid oid = new Oid(useKerberosOid ? KERBEROS_OID : SPNEGO_OID);
-
- byte[] token = getToken(authPolicy, spn, oid);
- return HttpAuthHeader.AUTH_TYPE_NEGOTIATE + " " + Base64Utility.encode(token);
- } catch (LoginException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (GSSException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- /**
- * Create and return service ticket token
- *
- * @param authPolicy
- * @param context
- * @return
- * @throws GSSException
- * @throws LoginException
- */
- private byte[] getToken(AuthorizationPolicy authPolicy, final GSSContext context) throws GSSException,
- LoginException {
- final byte[] token = new byte[0];
-
- if (authPolicy.getUserName() == null || authPolicy.getUserName().trim().length() == 0) {
- return context.initSecContext(token, 0, token.length);
- }
-
- if (lc == null) {
- lc = new LoginContext(authPolicy.getAuthorization(), getUsernamePasswordHandler(
- authPolicy.getUserName(), authPolicy.getPassword()));
- lc.login();
- }
-
- try {
- return (byte[])Subject.doAs(lc.getSubject(), new CreateServiceTicketAction(context, token));
- } catch (PrivilegedActionException e) {
- if (e.getCause() instanceof GSSException) {
- throw (GSSException) e.getCause();
- }
- LOG.log(Level.SEVERE, "initSecContext", e);
- return null;
- }
- }
-
- /**
- * Create and return a service ticket token for a given service principal
- * name
- *
- * @param authPolicy
- * @param spn
- * @return service ticket token
- * @throws GSSException
- * @throws LoginException
- */
- private byte[] getToken(AuthorizationPolicy authPolicy, String spn, Oid oid) throws GSSException,
- LoginException {
- GSSManager manager = GSSManager.getInstance();
- GSSName serverName = manager.createName(spn, null);
-
- GSSContext context = manager
- .createContext(serverName.canonicalize(oid), oid, null, GSSContext.DEFAULT_LIFETIME);
- // TODO Do we need mutual auth. Will the code we have really work with
- // mutual auth?
- context.requestMutualAuth(true);
- // TODO Credential delegation could be a security hole if it was not
- // intended. Both settings should be configurable
- context.requestCredDeleg(true);
-
- return getToken(authPolicy, context);
- }
-
- private final class CreateServiceTicketAction implements PrivilegedExceptionAction<byte[]> {
- private final GSSContext context;
- private final byte[] token;
-
- private CreateServiceTicketAction(GSSContext context, byte[] token) {
- this.context = context;
- this.token = token;
- }
-
- public byte[] run() throws GSSException {
- return context.initSecContext(token, 0, token.length);
- }
- }
-
- public static CallbackHandler getUsernamePasswordHandler(final String username, final String password) {
- final CallbackHandler handler = new CallbackHandler() {
-
- public void handle(final Callback[] callback) {
- for (int i = 0; i < callback.length; i++) {
- if (callback[i] instanceof NameCallback) {
- final NameCallback nameCallback = (NameCallback) callback[i];
- nameCallback.setName(username);
- } else if (callback[i] instanceof PasswordCallback) {
- final PasswordCallback passCallback = (PasswordCallback) callback[i];
- passCallback.setPassword(password.toCharArray());
- }
- }
- }
- };
- return handler;
+ return super.getAuthorization(authPolicy, currentURL, message);
}
}
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.security;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.security.KerberosAuthenticationFilter;
+import org.apache.cxf.systest.jaxrs.BookStore;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.testutil.common.TestUtil;
+
+public class BookKerberosServer extends AbstractBusTestServerBase {
+ public static final String PORT = TestUtil.getPortNumber("jaxrs-kerberos");
+
+ protected void run() {
+
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(BookStore.class);
+ //default lifecycle is per-request, change it to singleton
+ sf.setResourceProvider(BookStore.class,
+ new SingletonResourceProvider(new BookStore()));
+ KerberosAuthenticationFilter filter = new KerberosAuthenticationFilter();
+ filter.setLoginContextName("KerberosServer");
+ filter.setCallbackHandler(getCallbackHandler("HTTP/localhost", "http"));
+ sf.setProvider(filter);
+ sf.setAddress("http://localhost:" + PORT + "/");
+
+ sf.create();
+ }
+
+ public static void main(String[] args) {
+ try {
+ BookKerberosServer s = new BookKerberosServer();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+
+ public static CallbackHandler getCallbackHandler(final String username, final String password) {
+ final CallbackHandler handler = new CallbackHandler() {
+
+ public void handle(final Callback[] callback) {
+ for (int i = 0; i < callback.length; i++) {
+ if (callback[i] instanceof NameCallback) {
+ final NameCallback nameCallback = (NameCallback) callback[i];
+ nameCallback.setName(username);
+ } else if (callback[i] instanceof PasswordCallback) {
+ final PasswordCallback passCallback = (PasswordCallback) callback[i];
+ passCallback.setPassword(password.toCharArray());
+ }
+ }
+ }
+ };
+ return handler;
+ }
+}
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/BookKerberosServer.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java Tue Jul 17 22:14:35 2012
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.systest.jaxrs.security;
+
+import org.apache.cxf.configuration.security.AuthorizationPolicy;
+import org.apache.cxf.interceptor.LoggingOutInterceptor;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.security.KerberosAuthOutInterceptor;
+import org.apache.cxf.systest.jaxrs.Book;
+import org.apache.cxf.systest.jaxrs.BookStore;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.http.auth.HttpAuthHeader;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class JAXRSKerberosBookTest extends AbstractBusClientServerTestBase {
+ public static final String PORT = BookKerberosServer.PORT;
+
+ private static final String KERBEROS_CONFIG_FILE =
+ "org/apache/cxf/systest/jaxrs/security/kerberosClient.xml";
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ String jaasConfig = JAXRSKerberosBookTest.class
+ .getResource("/org/apache/cxf/systest/jaxrs/security/kerberos.cfg").toURI().getPath();
+ System.setProperty("java.security.auth.login.config", jaasConfig);
+
+ assertTrue("server did not launch correctly",
+ launchServer(BookKerberosServer.class, true));
+ }
+
+ @Test
+ @Ignore
+ public void testGetBookWithConfigInHttpConduit() throws Exception {
+ doTestGetBook123Proxy(KERBEROS_CONFIG_FILE);
+ }
+
+ private void doTestGetBook123Proxy(String configFile) throws Exception {
+ BookStore bs = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class,
+ configFile);
+ WebClient.getConfig(bs).getOutInterceptors().add(new LoggingOutInterceptor());
+ // just to verify the interface call goes through CGLIB proxy too
+ assertEquals("http://localhost:" + PORT, WebClient.client(bs).getBaseURI().toString());
+ Book b = bs.getBook("123");
+ assertEquals(b.getId(), 123);
+ b = bs.getBook("123");
+ assertEquals(b.getId(), 123);
+ }
+
+ @Test
+ @Ignore
+ public void testGetBookWithInterceptor() throws Exception {
+ WebClient wc = WebClient.create("http://localhost:" + PORT + "/bookstore/books/123");
+
+ KerberosAuthOutInterceptor kbInterceptor = new KerberosAuthOutInterceptor();
+
+ AuthorizationPolicy policy = new AuthorizationPolicy();
+ policy.setAuthorizationType(HttpAuthHeader.AUTH_TYPE_NEGOTIATE);
+ policy.setAuthorization("KerberosClient");
+ policy.setUserName("alice");
+ policy.setPassword("alice");
+
+ kbInterceptor.setPolicy(policy);
+
+ WebClient.getConfig(wc).getOutInterceptors().add(new LoggingOutInterceptor());
+ WebClient.getConfig(wc).getOutInterceptors().add(kbInterceptor);
+
+ Book b = wc.get(Book.class);
+ assertEquals(b.getId(), 123);
+ }
+}
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/JAXRSKerberosBookTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberos.cfg
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberos.cfg?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberos.cfg (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberos.cfg Tue Jul 17 22:14:35 2012
@@ -0,0 +1,6 @@
+KerberosClient {
+ com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
+};
+KerberosServer {
+ com.sun.security.auth.module.Krb5LoginModule required storeKey=true;
+};
Added: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml?rev=1362686&view=auto
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml (added)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml Tue Jul 17 22:14:35 2012
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
+ http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
+ http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
+ ">
+
+ <!-- -->
+ <!-- HTTP/S configuration for proxy clients -->
+ <!-- -->
+ <http:conduit name="{http://jaxrs.systest.cxf.apache.org/}BookStore.http-conduit">
+ <http:client ConnectionTimeout="3000000" ReceiveTimeout="3000000"/>
+ <http:authorization>
+ <sec:UserName>alice</sec:UserName>
+ <sec:Password>alice</sec:Password>
+ <sec:AuthorizationType>Negotiate</sec:AuthorizationType>
+ <sec:Authorization>KerberosClient</sec:Authorization>
+ </http:authorization>
+ </http:conduit>
+
+ <!-- -->
+ <!-- HTTP/S configuration for web clients -->
+ <!--
+
+ <http:conduit name="\{https://localhost\:.*\}WebClient\.http-conduit">
+ <http:client ConnectionTimeout="3000000" ReceiveTimeout="3000000"/>
+ <authorization>
+ <AuthorizationType>Negotiate</AuthorizationType>
+ <Authorization>KerberosClient</Authorization>
+ <UserName>alice</UserName>
+ <Password>alice</Password>
+ </authorization>
+ </http:conduit>
+ -->
+</beans>
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml
------------------------------------------------------------------------------
svn:keywords = Rev Date
Propchange: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/security/kerberosClient.xml
------------------------------------------------------------------------------
svn:mime-type = text/xml