You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by cs...@apache.org on 2010/11/14 22:44:25 UTC
svn commit: r1035078 -
/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java
Author: cschneider
Date: Sun Nov 14 21:44:25 2010
New Revision: 1035078
URL: http://svn.apache.org/viewvc?rev=1035078&view=rev
Log:
CXF-3123 initial commit of spnego auth with thanks to luca di stefano
Added:
cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java (with props)
Added: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java?rev=1035078&view=auto
==============================================================================
--- cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java (added)
+++ cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java Sun Nov 14 21:44:25 2010
@@ -0,0 +1,226 @@
+/**
+ * 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;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+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.configuration.security.ProxyAuthorizationPolicy;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.interceptor.MessageSenderInterceptor;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.Phase;
+import org.apache.cxf.phase.PhaseInterceptor;
+import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
+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 HttpSpnegoAuthInterceptor implements PhaseInterceptor<Message> {
+
+ 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 final String AUTH_NEGOTIATE_SCHEMA = "Negotiate";
+
+ 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(HTTPConduit.class);
+
+ private static final Set<String> BEFORE = new HashSet<String>();
+ static {
+ BEFORE.add(MessageSenderInterceptor.class.getName());
+ }
+
+
+
+ public void handleMessage(Message message) throws Fault {
+ try {
+ HTTPConduit conduit = (HTTPConduit) message.getExchange().getConduit(message);
+ addNegotiationAuth(conduit, message.getDestination().getAddress().getAddress().getValue());
+ } catch (PrivilegedActionException e) {
+ throw new Fault(e);
+ } catch (GSSException e) {
+ throw new Fault(e);
+ } catch (MalformedURLException e) {
+ throw new Fault(e);
+ } catch (LoginException e) {
+ throw new Fault(e);
+ }
+ }
+
+ public void addNegotiationAuth(HTTPConduit http, String address) throws PrivilegedActionException,
+ GSSException, MalformedURLException, LoginException {
+ HTTPClientPolicy httpClientPolicy = http.getClient();
+
+ if (httpClientPolicy.getProxyServer() != null) {
+ ProxyAuthorizationPolicy proxyAuthPolicy = http.getProxyAuthorization();
+ if (proxyAuthPolicy != null && AUTH_NEGOTIATE_SCHEMA.equals(
+ proxyAuthPolicy.getAuthorizationType())) {
+ String proxyServicePrincipalName = "HTTP/" + httpClientPolicy.getProxyServer();
+ LOG.fine("Adding http proxy authorization service ticket for service principal name: "
+ + proxyServicePrincipalName);
+ byte[] token = getToken(proxyAuthPolicy, proxyServicePrincipalName);
+ proxyAuthPolicy.setAuthorization(Base64Utility.encode(token));
+ }
+ }
+
+ AuthorizationPolicy authPolicy = http.getAuthorization();
+ if (authPolicy != null && AUTH_NEGOTIATE_SCHEMA.equals(authPolicy.getAuthorizationType())) {
+ String spn = "HTTP/" + new URL(address).getHost();
+ LOG.fine("Adding authorization service ticket for service principal name: " + spn);
+ byte[] token = getToken(authPolicy, spn);
+ authPolicy.setAuthorization(Base64Utility.encode(token));
+ }
+ }
+
+ 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;
+ }
+
+ /**
+ * 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);
+ }
+
+ // here only if we don't have a cached token and we pass credentials
+ // through authPolicy
+ 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 proxyAuthPolicy
+ * @param spn
+ * @return service ticket token
+ * @throws GSSException
+ * @throws LoginException
+ */
+ private byte[] getToken(AuthorizationPolicy proxyAuthPolicy, String spn) throws GSSException,
+ LoginException {
+ GSSManager manager = GSSManager.getInstance();
+ GSSName serverName = manager.createName(spn, null);
+
+ // TODO Is it correct to use kerberos oid instead of spnego here?
+ Oid oid = new Oid(KERBEROS_OID);
+
+ 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(proxyAuthPolicy, context);
+ }
+
+ public Set<String> getAfter() {
+ return Collections.emptySet();
+ }
+
+ public Set<String> getBefore() {
+ return BEFORE;
+ }
+
+ public String getId() {
+ return HttpSpnegoAuthInterceptor.class.getName();
+ }
+
+ public String getPhase() {
+ return Phase.PREPARE_SEND;
+ }
+
+ public void handleFault(Message message) {
+
+ }
+}
Propchange: cxf/trunk/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpSpnegoAuthInterceptor.java
------------------------------------------------------------------------------
svn:mime-type = text/plain