mirror of https://github.com/apache/activemq.git
Applied patch at https://issues.apache.org/jira/browse/AMQ-3321 : Add kerberos authentication support for transport over https
git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1126702 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
975fc55b2a
commit
2528015fa3
|
@ -19,7 +19,6 @@ package org.apache.activemq.transport.https;
|
|||
import java.net.URI;
|
||||
|
||||
import org.apache.activemq.transport.http.HttpTransportServer;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
|
||||
public class HttpsTransportServer extends HttpTransportServer {
|
||||
|
||||
|
@ -31,13 +30,19 @@ public class HttpsTransportServer extends HttpTransportServer {
|
|||
private String trustCertificateAlgorithm;
|
||||
private String keyCertificateAlgorithm;
|
||||
private String protocol;
|
||||
private String auth;
|
||||
|
||||
public HttpsTransportServer(URI uri, HttpsTransportFactory factory) {
|
||||
public HttpsTransportServer(URI uri, HttpsTransportFactory factory) {
|
||||
super(uri, factory);
|
||||
}
|
||||
|
||||
public void doStart() throws Exception {
|
||||
SslSocketConnector sslConnector = new SslSocketConnector();
|
||||
Krb5AndCertsSslSocketConnector sslConnector = new Krb5AndCertsSslSocketConnector();
|
||||
|
||||
if(auth != null){
|
||||
sslConnector.setMode(auth);
|
||||
}
|
||||
|
||||
sslConnector.setKeystore(keyStore);
|
||||
sslConnector.setPassword(keyStorePassword);
|
||||
// if the keyPassword hasn't been set, default it to the
|
||||
|
@ -60,7 +65,7 @@ public class HttpsTransportServer extends HttpTransportServer {
|
|||
if (protocol != null) {
|
||||
sslConnector.setProtocol(protocol);
|
||||
}
|
||||
|
||||
|
||||
setConnector(sslConnector);
|
||||
|
||||
super.doStart();
|
||||
|
@ -133,4 +138,18 @@ public class HttpsTransportServer extends HttpTransportServer {
|
|||
this.trustCertificateAlgorithm = trustCertificateAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the auth
|
||||
*/
|
||||
public String getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param auth the auth to set
|
||||
*/
|
||||
public void setAuth(String auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* 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.activemq.transport.https;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.http.HttpSchemes;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.ssl.ServletSSL;
|
||||
import org.eclipse.jetty.server.ssl.SslSocketConnector;
|
||||
|
||||
/**
|
||||
* Extend Jetty's {@link SslSocketConnector} to optionally also provide
|
||||
* Kerberos5ized SSL sockets. The only change in behavior from superclass
|
||||
* is that we no longer honor requests to turn off NeedAuthentication when
|
||||
* running with Kerberos support.
|
||||
*/
|
||||
public class Krb5AndCertsSslSocketConnector extends SslSocketConnector {
|
||||
public static final List<String> KRB5_CIPHER_SUITES =
|
||||
Collections.unmodifiableList(Collections.singletonList(
|
||||
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA"));
|
||||
static {
|
||||
System.setProperty("https.cipherSuites", KRB5_CIPHER_SUITES.get(0));
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Krb5AndCertsSslSocketConnector.class);
|
||||
|
||||
private static final String REMOTE_PRINCIPAL = "remote_principal";
|
||||
|
||||
public enum MODE {KRB, CERTS, BOTH} // Support Kerberos, certificates or both?
|
||||
|
||||
private boolean useKrb;
|
||||
private boolean useCerts;
|
||||
|
||||
public Krb5AndCertsSslSocketConnector() {
|
||||
// By default, stick to cert based authentication
|
||||
super();
|
||||
useKrb = false;
|
||||
useCerts = true;
|
||||
setPasswords();
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
useKrb = mode == MODE.KRB.toString() || mode == MODE.BOTH.toString();
|
||||
useCerts = mode == MODE.CERTS.toString() || mode == MODE.BOTH.toString();
|
||||
logIfDebug("useKerb = " + useKrb + ", useCerts = " + useCerts);
|
||||
}
|
||||
|
||||
// If not using Certs, set passwords to random gibberish or else
|
||||
// Jetty will actually prompt the user for some.
|
||||
private void setPasswords() {
|
||||
if(!useCerts) {
|
||||
Random r = new Random();
|
||||
System.setProperty("jetty.ssl.password", String.valueOf(r.nextLong()));
|
||||
System.setProperty("jetty.ssl.keypassword", String.valueOf(r.nextLong()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLServerSocketFactory createFactory() throws Exception {
|
||||
if(useCerts)
|
||||
return super.createFactory();
|
||||
|
||||
SSLContext context = super.getProvider()==null
|
||||
? SSLContext.getInstance(super.getProtocol())
|
||||
:SSLContext.getInstance(super.getProtocol(), super.getProvider());
|
||||
context.init(null, null, null);
|
||||
|
||||
System.err.println("Creating socket factory");
|
||||
return context.getServerSocketFactory();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mortbay.jetty.security.SslSocketConnector#newServerSocket(java.lang.String, int, int)
|
||||
*/
|
||||
@Override
|
||||
protected ServerSocket newServerSocket(String host, int port, int backlog)
|
||||
throws IOException {
|
||||
System.err.println("Creating new KrbServerSocket for: " + host);
|
||||
logIfDebug("Creating new KrbServerSocket for: " + host);
|
||||
SSLServerSocket ss = null;
|
||||
|
||||
if(useCerts) // Get the server socket from the SSL super impl
|
||||
ss = (SSLServerSocket)super.newServerSocket(host, port, backlog);
|
||||
else { // Create a default server socket
|
||||
try {
|
||||
ss = (SSLServerSocket)(host == null
|
||||
? createFactory().createServerSocket(port, backlog) :
|
||||
createFactory().createServerSocket(port, backlog, InetAddress.getByName(host)));
|
||||
} catch (Exception e)
|
||||
{
|
||||
LOG.warn("Could not create KRB5 Listener", e);
|
||||
throw new IOException("Could not create KRB5 Listener: " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Add Kerberos ciphers to this socket server if needed.
|
||||
if(useKrb) {
|
||||
ss.setNeedClientAuth(true);
|
||||
String [] combined;
|
||||
if(useCerts) { // combine the cipher suites
|
||||
String[] certs = ss.getEnabledCipherSuites();
|
||||
combined = new String[certs.length + KRB5_CIPHER_SUITES.size()];
|
||||
System.arraycopy(certs, 0, combined, 0, certs.length);
|
||||
System.arraycopy(KRB5_CIPHER_SUITES.toArray(new String[0]), 0, combined,
|
||||
certs.length, KRB5_CIPHER_SUITES.size());
|
||||
} else { // Just enable Kerberos auth
|
||||
combined = KRB5_CIPHER_SUITES.toArray(new String[0]);
|
||||
}
|
||||
|
||||
ss.setEnabledCipherSuites(combined);
|
||||
}
|
||||
System.err.println("New socket created");
|
||||
return ss;
|
||||
};
|
||||
|
||||
@Override
|
||||
public void customize(EndPoint endpoint, Request request) throws IOException {
|
||||
if(useKrb) { // Add Kerberos-specific info
|
||||
SSLSocket sslSocket = (SSLSocket)endpoint.getTransport();
|
||||
Principal remotePrincipal = sslSocket.getSession().getPeerPrincipal();
|
||||
logIfDebug("Remote principal = " + remotePrincipal);
|
||||
request.setScheme(HttpSchemes.HTTPS);
|
||||
request.setAttribute(REMOTE_PRINCIPAL, remotePrincipal);
|
||||
|
||||
if(!useCerts) { // Add extra info that would have been added by super
|
||||
String cipherSuite = sslSocket.getSession().getCipherSuite();
|
||||
Integer keySize = Integer.valueOf(ServletSSL.deduceKeyLength(cipherSuite));;
|
||||
|
||||
request.setAttribute("javax.servlet.request.cipher_suite", cipherSuite);
|
||||
request.setAttribute("javax.servlet.request.key_size", keySize);
|
||||
}
|
||||
}
|
||||
|
||||
if(useCerts) super.customize(endpoint, request);
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
private void logIfDebug(String s) {
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug(s);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue