Commit 9a73f871 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Added support for validating certificates of BOSH clients. JM-1390

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@10511 b35dd754-fafc-0310-a699-88a17e54d16e
parent 6b109ac1
...@@ -16,8 +16,8 @@ import org.jivesoftware.openfire.auth.UnauthorizedException; ...@@ -16,8 +16,8 @@ import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.session.LocalSession; import org.jivesoftware.openfire.session.LocalSession;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import javax.net.ssl.SSLSession;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.Certificate;
/** /**
* Represents a connection on the server. * Represents a connection on the server.
...@@ -90,11 +90,11 @@ public interface Connection { ...@@ -90,11 +90,11 @@ public interface Connection {
public String getHostName() throws UnknownHostException; public String getHostName() throws UnknownHostException;
/** /**
* Returns the underlying {@link SSLSession} for the connection. * Returns the underlying {@link javax.security.cert.X509Certificate} for the connection.
* *
* @return <tt>null</tt> if no {@link SSLSession} is initialized yet. * @return <tt>null</tt> if no {@link javax.security.cert.X509Certificate} is present for the connection.
*/ */
public SSLSession getSSLSession(); public Certificate[] getPeerCertificates();
/** /**
* Close this session including associated socket connection. The order of * Close this session including associated socket connection. The order of
......
...@@ -20,6 +20,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager; ...@@ -20,6 +20,7 @@ import org.jivesoftware.openfire.cluster.ClusterManager;
import org.jivesoftware.openfire.component.InternalComponentManager; import org.jivesoftware.openfire.component.InternalComponentManager;
import org.jivesoftware.openfire.container.BasicModule; import org.jivesoftware.openfire.container.BasicModule;
import org.jivesoftware.openfire.event.SessionEventDispatcher; import org.jivesoftware.openfire.event.SessionEventDispatcher;
import org.jivesoftware.openfire.http.HttpConnection;
import org.jivesoftware.openfire.http.HttpSession; import org.jivesoftware.openfire.http.HttpSession;
import org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager; import org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager;
import org.jivesoftware.openfire.server.OutgoingSessionPromise; import org.jivesoftware.openfire.server.OutgoingSessionPromise;
...@@ -315,14 +316,13 @@ public class SessionManager extends BasicModule implements ClusterEventListener ...@@ -315,14 +316,13 @@ public class SessionManager extends BasicModule implements ClusterEventListener
return session; return session;
} }
public HttpSession createClientHttpSession(long rid, InetAddress address, StreamID id) public HttpSession createClientHttpSession(long rid, InetAddress address, StreamID id, HttpConnection connection)
throws UnauthorizedException throws UnauthorizedException {
{
if (serverName == null) { if (serverName == null) {
throw new UnauthorizedException("Server not initialized"); throw new UnauthorizedException("Server not initialized");
} }
PacketDeliverer backupDeliverer = server.getPacketDeliverer(); PacketDeliverer backupDeliverer = server.getPacketDeliverer();
HttpSession session = new HttpSession(backupDeliverer, serverName, address, id, rid); HttpSession session = new HttpSession(backupDeliverer, serverName, address, id, rid, connection);
Connection conn = session.getConnection(); Connection conn = session.getConnection();
conn.init(session); conn.init(session);
conn.registerCloseListener(clientSessionListener, session); conn.registerCloseListener(clientSessionListener, session);
......
...@@ -12,11 +12,12 @@ ...@@ -12,11 +12,12 @@
package org.jivesoftware.openfire.http; package org.jivesoftware.openfire.http;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.util.JiveGlobals;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException; import java.io.IOException;
/** /**
...@@ -27,23 +28,73 @@ import java.io.IOException; ...@@ -27,23 +28,73 @@ import java.io.IOException;
*/ */
public class FlashCrossDomainServlet extends HttpServlet { public class FlashCrossDomainServlet extends HttpServlet {
public static String CROSS_DOMAIN_TEXT = "<?xml version=\"1.0\"?>" + private static String CROSS_DOMAIN_TEXT = "<?xml version=\"1.0\"?>" +
"<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">" + "<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">" +
"<cross-domain-policy>" + "<cross-domain-policy>" +
"<site-control permitted-cross-domain-policies=\"all\"/>" +
"<allow-access-from domain=\"*\" to-ports=\""; "<allow-access-from domain=\"*\" to-ports=\"";
public static String CROSS_DOMAIN_END_TEXT = "\" /></cross-domain-policy>"; private static String CROSS_DOMAIN_MIDDLE_TEXT = "\" secure=\"";
private static String CROSS_DOMAIN_END_TEXT = "\"/></cross-domain-policy>";
private static String CROSS_DOMAIN_SECURE_ENABLED = "httpbind.crossdomain.secure";
private static boolean CROSS_DOMAIN_SECURE_DEFAULT = true;
@Override @Override
protected void doGet(HttpServletRequest httpServletRequest, protected void doGet(HttpServletRequest httpServletRequest,
HttpServletResponse response) throws HttpServletResponse response) throws
ServletException, IOException { ServletException, IOException {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(CROSS_DOMAIN_TEXT + builder.append(CROSS_DOMAIN_TEXT);
XMPPServer.getInstance().getConnectionManager().getClientListenerPort() + getPortList(builder);
CROSS_DOMAIN_END_TEXT); builder.append(CROSS_DOMAIN_MIDDLE_TEXT);
getSecure(builder);
builder.append(CROSS_DOMAIN_END_TEXT);
builder.append("\n"); builder.append("\n");
response.setContentType("text/xml"); response.setContentType("text/xml");
response.getOutputStream().write(builder.toString().getBytes()); response.getOutputStream().write(builder.toString().getBytes());
} }
private StringBuilder getPortList(StringBuilder builder) {
boolean multiple = false;
if(XMPPServer.getInstance().getConnectionManager().getClientListenerPort() > 0) {
builder.append(XMPPServer.getInstance().getConnectionManager().getClientListenerPort());
multiple = true;
}
if(XMPPServer.getInstance().getConnectionManager().getClientSSLListenerPort() > 0) {
if(multiple) {
builder.append(",");
}
builder.append(XMPPServer.getInstance().getConnectionManager().getClientSSLListenerPort());
multiple = true;
}
if(HttpBindManager.getInstance().isHttpBindEnabled()) {
// ports for http-binding may not be strictly needed in here, but it doesn't hurt
if(HttpBindManager.getInstance().getHttpBindUnsecurePort() > 0) {
if(multiple) {
builder.append(",");
}
builder.append(HttpBindManager.getInstance().getHttpBindUnsecurePort());
multiple = true;
}
if(HttpBindManager.getInstance().getHttpBindSecurePort() > 0) {
if(multiple) {
builder.append(",");
}
builder.append(HttpBindManager.getInstance().getHttpBindSecurePort());
}
}
return builder;
}
private StringBuilder getSecure(StringBuilder builder) {
if (JiveGlobals.getBooleanProperty(CROSS_DOMAIN_SECURE_ENABLED,CROSS_DOMAIN_SECURE_DEFAULT)) {
builder.append("true");
} else {
builder.append("false");
}
return builder;
}
} }
...@@ -25,6 +25,7 @@ import org.mortbay.jetty.nio.SelectChannelConnector; ...@@ -25,6 +25,7 @@ import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.security.SslSelectChannelConnector; import org.mortbay.jetty.security.SslSelectChannelConnector;
import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.webapp.WebAppContext; import org.mortbay.jetty.webapp.WebAppContext;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import java.io.File; import java.io.File;
import java.security.KeyStore; import java.security.KeyStore;
...@@ -145,9 +146,20 @@ public final class HttpBindManager { ...@@ -145,9 +146,20 @@ public final class HttpBindManager {
sslConnector.setTrustPassword(SSLConfig.getc2sTrustPassword()); sslConnector.setTrustPassword(SSLConfig.getc2sTrustPassword());
sslConnector.setTruststoreType(SSLConfig.getStoreType()); sslConnector.setTruststoreType(SSLConfig.getStoreType());
sslConnector.setTruststore(SSLConfig.getc2sTruststoreLocation()); sslConnector.setTruststore(SSLConfig.getc2sTruststoreLocation());
sslConnector.setNeedClientAuth(false);
sslConnector.setWantClientAuth(false);
// Set policy for checking client certificates
String certPol = JiveGlobals.getProperty("xmpp.client.cert.policy", "disabled");
if(certPol.equals("needed")) {
sslConnector.setNeedClientAuth(true);
sslConnector.setWantClientAuth(true);
} else if(certPol.equals("wanted")) {
sslConnector.setNeedClientAuth(false);
sslConnector.setWantClientAuth(true);
} else {
sslConnector.setNeedClientAuth(false);
sslConnector.setWantClientAuth(false);
}
sslConnector.setKeyPassword(SSLConfig.getKeyPassword()); sslConnector.setKeyPassword(SSLConfig.getKeyPassword());
sslConnector.setKeystoreType(SSLConfig.getStoreType()); sslConnector.setKeystoreType(SSLConfig.getStoreType());
sslConnector.setKeystore(SSLConfig.getKeystoreLocation()); sslConnector.setKeystore(SSLConfig.getKeystoreLocation());
...@@ -474,7 +486,7 @@ public final class HttpBindManager { ...@@ -474,7 +486,7 @@ public final class HttpBindManager {
@Override @Override
protected SSLContext createSSLContext() throws Exception { protected SSLContext createSSLContext() throws Exception {
return SSLConfig.getSSLContext(); return SSLConfig.getc2sSSLContext();
} }
} }
......
...@@ -11,29 +11,30 @@ ...@@ -11,29 +11,30 @@
package org.jivesoftware.openfire.http; package org.jivesoftware.openfire.http;
import org.xmlpull.v1.XmlPullParserFactory; import org.apache.commons.lang.StringEscapeUtils;
import org.xmlpull.v1.XmlPullParserException;
import org.jivesoftware.util.Log;
import org.jivesoftware.openfire.net.MXParser;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.dom4j.io.XMPPPacketReader;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.DocumentException; import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.DocumentHelper; import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMPPPacketReader;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.net.MXParser;
import org.jivesoftware.util.Log;
import org.mortbay.util.ajax.ContinuationSupport; import org.mortbay.util.ajax.ContinuationSupport;
import org.apache.commons.lang.StringEscapeUtils; import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException; import java.io.ByteArrayInputStream;
import javax.servlet.ServletConfig;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.security.cert.X509Certificate;
/** /**
* Servlet which handles requests to the HTTP binding service. It determines if there is currently * Servlet which handles requests to the HTTP binding service. It determines if there is currently
...@@ -261,7 +262,9 @@ public class HttpBindServlet extends HttpServlet { ...@@ -261,7 +262,9 @@ public class HttpBindServlet extends HttpServlet {
} }
try { try {
HttpConnection connection = new HttpConnection(rid, request.isSecure()); X509Certificate[] certificates =
(X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
HttpConnection connection = new HttpConnection(rid, request.isSecure(), certificates);
InetAddress address = InetAddress.getByName(request.getRemoteAddr()); InetAddress address = InetAddress.getByName(request.getRemoteAddr());
connection.setSession(sessionManager.createSession(address, rootNode, connection)); connection.setSession(sessionManager.createSession(address, rootNode, connection));
respond(response, connection, request.getMethod()); respond(response, connection, request.getMethod());
......
...@@ -14,6 +14,8 @@ package org.jivesoftware.openfire.http; ...@@ -14,6 +14,8 @@ package org.jivesoftware.openfire.http;
import org.mortbay.util.ajax.Continuation; import org.mortbay.util.ajax.Continuation;
import java.security.cert.X509Certificate;
/** /**
* Represents one HTTP connection with a client using the HTTP Binding service. The client will wait * Represents one HTTP connection with a client using the HTTP Binding service. The client will wait
* on {@link #getResponse()} until the server forwards a message to it or the wait time on the * on {@link #getResponse()} until the server forwards a message to it or the wait time on the
...@@ -29,6 +31,7 @@ public class HttpConnection { ...@@ -29,6 +31,7 @@ public class HttpConnection {
private boolean isClosed; private boolean isClosed;
private boolean isSecure = false; private boolean isSecure = false;
private boolean isDelivered; private boolean isDelivered;
private X509Certificate[] sslCertificates;
private static final String CONNECTION_CLOSED = "connection closed"; private static final String CONNECTION_CLOSED = "connection closed";
...@@ -37,11 +40,13 @@ public class HttpConnection { ...@@ -37,11 +40,13 @@ public class HttpConnection {
* *
* @param requestId the ID which uniquely identifies this request. * @param requestId the ID which uniquely identifies this request.
* @param isSecure true if this connection is using HTTPS * @param isSecure true if this connection is using HTTPS
* @param sslCertificates list of certificates presented by the client.
*/ */
public HttpConnection(long requestId, boolean isSecure) { public HttpConnection(long requestId, boolean isSecure, X509Certificate[] sslCertificates) {
this.requestId = requestId; this.requestId = requestId;
this.isSecure = isSecure; this.isSecure = isSecure;
this.isDelivered = false; this.isDelivered = false;
this.sslCertificates = sslCertificates;
} }
/** /**
...@@ -165,6 +170,15 @@ public class HttpConnection { ...@@ -165,6 +170,15 @@ public class HttpConnection {
public HttpSession getSession() { public HttpSession getSession() {
return session; return session;
} }
/**
* Returns the peer certificates for this connection.
*
* @return the peer certificates for this connection or null.
*/
public X509Certificate[] getPeerCertificates() {
return sslCertificates;
}
void setContinuation(Continuation continuation) { void setContinuation(Continuation continuation) {
this.continuation = continuation; this.continuation = continuation;
......
...@@ -38,6 +38,8 @@ import java.io.StringReader; ...@@ -38,6 +38,8 @@ import java.io.StringReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.*; import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
...@@ -88,6 +90,7 @@ public class HttpSession extends LocalClientSession { ...@@ -88,6 +90,7 @@ public class HttpSession extends LocalClientSession {
private int maxRequests; private int maxRequests;
private PacketDeliverer backupDeliverer; private PacketDeliverer backupDeliverer;
private Double version = Double.NaN; private Double version = Double.NaN;
private X509Certificate[] sslCertificates;
private final Queue<Collection<Element>> packetsToSend = new LinkedList<Collection<Element>>(); private final Queue<Collection<Element>> packetsToSend = new LinkedList<Collection<Element>>();
// Semaphore which protects the packets to send, so, there can only be one consumer at a time. // Semaphore which protects the packets to send, so, there can only be one consumer at a time.
...@@ -101,12 +104,13 @@ public class HttpSession extends LocalClientSession { ...@@ -101,12 +104,13 @@ public class HttpSession extends LocalClientSession {
}; };
public HttpSession(PacketDeliverer backupDeliverer, String serverName, InetAddress address, public HttpSession(PacketDeliverer backupDeliverer, String serverName, InetAddress address,
StreamID streamID, long rid) { StreamID streamID, long rid, HttpConnection connection) {
super(serverName, null, streamID); super(serverName, null, streamID);
conn = new HttpVirtualConnection(address); conn = new HttpVirtualConnection(address);
this.lastActivity = System.currentTimeMillis(); this.lastActivity = System.currentTimeMillis();
this.lastRequestID = rid; this.lastRequestID = rid;
this.backupDeliverer = backupDeliverer; this.backupDeliverer = backupDeliverer;
this.sslCertificates = connection.getPeerCertificates();
} }
/** /**
...@@ -470,6 +474,15 @@ public class HttpSession extends LocalClientSession { ...@@ -470,6 +474,15 @@ public class HttpSession extends LocalClientSession {
} }
} }
} }
/**
* Return the X509Certificates associated with this session.
*
* @return the X509Certificate associated with this session.
*/
public X509Certificate[] getPeerCertificates() {
return sslCertificates;
}
/** /**
* Creates a new connection on this session. If a response is currently available for this * Creates a new connection on this session. If a response is currently available for this
...@@ -491,7 +504,7 @@ public class HttpSession extends LocalClientSession { ...@@ -491,7 +504,7 @@ public class HttpSession extends LocalClientSession {
boolean isSecure) boolean isSecure)
throws HttpConnectionClosedException, HttpBindException throws HttpConnectionClosedException, HttpBindException
{ {
HttpConnection connection = new HttpConnection(rid, isSecure); HttpConnection connection = new HttpConnection(rid, isSecure, sslCertificates);
if (rid <= lastRequestID) { if (rid <= lastRequestID) {
Delivered deliverable = retrieveDeliverable(rid); Delivered deliverable = retrieveDeliverable(rid);
if (deliverable == null) { if (deliverable == null) {
...@@ -540,6 +553,8 @@ public class HttpSession extends LocalClientSession { ...@@ -540,6 +553,8 @@ public class HttpSession extends LocalClientSession {
"connections on this session must be secured.", BoshBindingError.badRequest); "connections on this session must be secured.", BoshBindingError.badRequest);
} }
sslCertificates = connection.getPeerCertificates();
connection.setSession(this); connection.setSession(this);
// We aren't supposed to hold connections open or we already have some packets waiting // We aren't supposed to hold connections open or we already have some packets waiting
// to be sent to the client. // to be sent to the client.
...@@ -763,6 +778,10 @@ public class HttpSession extends LocalClientSession { ...@@ -763,6 +778,10 @@ public class HttpSession extends LocalClientSession {
public void deliverRawText(String text) { public void deliverRawText(String text) {
((HttpSession) session).deliver(text); ((HttpSession) session).deliver(text);
} }
public Certificate[] getPeerCertificates() {
return ((HttpSession) session).getPeerCertificates();
}
} }
private class Deliverable implements Comparable<Deliverable> { private class Deliverable implements Comparable<Deliverable> {
......
...@@ -122,7 +122,7 @@ public class HttpSessionManager { ...@@ -122,7 +122,7 @@ public class HttpSessionManager {
int hold = getIntAttribute(rootNode.attributeValue("hold"), 1); int hold = getIntAttribute(rootNode.attributeValue("hold"), 1);
double version = getDoubleAttribute(rootNode.attributeValue("ver"), 1.5); double version = getDoubleAttribute(rootNode.attributeValue("ver"), 1.5);
HttpSession session = createSession(connection.getRequestId(), address); HttpSession session = createSession(connection.getRequestId(), address, connection);
session.setWait(Math.min(wait, getMaxWait())); session.setWait(Math.min(wait, getMaxWait()));
session.setHold(hold); session.setHold(hold);
session.setSecure(connection.isSecure()); session.setSecure(connection.isSecure());
...@@ -233,11 +233,11 @@ public class HttpSessionManager { ...@@ -233,11 +233,11 @@ public class HttpSessionManager {
return connection; return connection;
} }
private HttpSession createSession(long rid, InetAddress address) throws UnauthorizedException { private HttpSession createSession(long rid, InetAddress address, HttpConnection connection) throws UnauthorizedException {
// Create a ClientSession for this user. // Create a ClientSession for this user.
StreamID streamID = SessionManager.getInstance().nextStreamID(); StreamID streamID = SessionManager.getInstance().nextStreamID();
// Send to the server that a new client session has been created // Send to the server that a new client session has been created
HttpSession session = sessionManager.createClientHttpSession(rid, address, streamID); HttpSession session = sessionManager.createClientHttpSession(rid, address, streamID, connection);
// Register that the new session is associated with the specified stream ID // Register that the new session is associated with the specified stream ID
sessionMap.put(streamID.getID(), session); sessionMap.put(streamID.getID(), session);
session.addSessionCloseListener(sessionListener); session.addSessionCloseListener(sessionListener);
......
...@@ -18,10 +18,10 @@ import org.dom4j.Namespace; ...@@ -18,10 +18,10 @@ import org.dom4j.Namespace;
import org.dom4j.QName; import org.dom4j.QName;
import org.jivesoftware.openfire.Connection; import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.auth.AuthFactory; import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.AuthToken; import org.jivesoftware.openfire.auth.AuthToken;
import org.jivesoftware.openfire.auth.AuthorizationManager; import org.jivesoftware.openfire.auth.AuthorizationManager;
import org.jivesoftware.openfire.lockout.LockOutManager;
import org.jivesoftware.openfire.session.*; import org.jivesoftware.openfire.session.*;
import org.jivesoftware.util.CertificateManager; import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
...@@ -29,16 +29,15 @@ import org.jivesoftware.util.Log; ...@@ -29,16 +29,15 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.JID; import org.xmpp.packet.JID;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.sasl.Sasl; import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException; import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServer;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.security.Security; import java.security.Security;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.*; import java.util.*;
import java.net.UnknownHostException;
/** /**
* SASLAuthentication is responsible for returning the available SASL mechanisms to use and for * SASLAuthentication is responsible for returning the available SASL mechanisms to use and for
...@@ -458,19 +457,16 @@ public class SASLAuthentication { ...@@ -458,19 +457,16 @@ public class SASLAuthentication {
} }
// Check that hostname matches the one provided in a certificate // Check that hostname matches the one provided in a certificate
SocketConnection connection = (SocketConnection) session.getConnection(); SocketConnection connection = (SocketConnection) session.getConnection();
try {
for (Certificate certificate : connection.getSSLSession().getPeerCertificates()) { for (Certificate certificate : connection.getPeerCertificates()) {
for (String identity : CertificateManager.getPeerIdentities((X509Certificate) certificate)) { for (String identity : CertificateManager.getPeerIdentities((X509Certificate) certificate)) {
if (identity.equals(hostname) || identity.equals("*." + hostname)) { if (identity.equals(hostname) || identity.equals("*." + hostname)) {
authenticationSuccessful(session, hostname, null); authenticationSuccessful(session, hostname, null);
return Status.authenticated; return Status.authenticated;
}
} }
} }
} }
catch (SSLPeerUnverifiedException e) {
Log.warn("Error retrieving client certificates of: " + session, e);
}
} }
else if (session instanceof LocalClientSession) { else if (session instanceof LocalClientSession) {
// Client EXTERNALL login // Client EXTERNALL login
...@@ -481,18 +477,14 @@ public class SASLAuthentication { ...@@ -481,18 +477,14 @@ public class SASLAuthentication {
String principal = ""; String principal = "";
ArrayList<String> principals = new ArrayList<String>(); ArrayList<String> principals = new ArrayList<String>();
Connection connection = session.getConnection(); Connection connection = session.getConnection();
if (connection.getSSLSession() == null) { if (connection.getPeerCertificates().length < 1) {
Log.debug("SASLAuthentication: EXTERNAL authentication requested, but no SSL/TLS connection found."); Log.debug("SASLAuthentication: EXTERNAL authentication requested, but no certificates found.");
authenticationFailed(session); authenticationFailed(session);
return Status.failed; return Status.failed;
} }
try {
for (Certificate certificate : connection.getSSLSession().getPeerCertificates()) { for (Certificate certificate : connection.getPeerCertificates()) {
principals.addAll(CertificateManager.getPeerIdentities((X509Certificate)certificate)); principals.addAll(CertificateManager.getPeerIdentities((X509Certificate)certificate));
}
}
catch (SSLPeerUnverifiedException e) {
Log.warn("Error retrieving client certificates of: " + session, e);
} }
if(principals.size() == 1) { if(principals.size() == 1) {
......
...@@ -27,7 +27,7 @@ import org.jivesoftware.util.LocaleUtils; ...@@ -27,7 +27,7 @@ import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
...@@ -35,6 +35,7 @@ import java.io.Writer; ...@@ -35,6 +35,7 @@ import java.io.Writer;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.channels.Channels; import java.nio.channels.Channels;
import java.security.cert.Certificate;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
...@@ -394,11 +395,16 @@ public class SocketConnection implements Connection { ...@@ -394,11 +395,16 @@ public class SocketConnection implements Connection {
this.flashClient = flashClient; this.flashClient = flashClient;
} }
public SSLSession getSSLSession() { public Certificate[] getPeerCertificates() {
if (tlsStreamHandler != null) { if (tlsStreamHandler != null) {
return tlsStreamHandler.getSSLSession(); try {
return tlsStreamHandler.getSSLSession().getPeerCertificates();
} catch (SSLPeerUnverifiedException e ) {
Log.warn("Error retrieving client certificates of: " + tlsStreamHandler.getSSLSession(), e);
//pretend tlsStreamHandler is null
}
} }
return null; return new Certificate[0];
} }
public PacketDeliverer getPacketDeliverer() { public PacketDeliverer getPacketDeliverer() {
...@@ -659,4 +665,4 @@ public class SocketConnection implements Connection { ...@@ -659,4 +665,4 @@ public class SocketConnection implements Connection {
public void setSocketReader(SocketReader socketReader) { public void setSocketReader(SocketReader socketReader) {
this.socketReader = socketReader; this.socketReader = socketReader;
} }
} }
\ No newline at end of file
...@@ -20,7 +20,7 @@ import org.jivesoftware.openfire.session.Session; ...@@ -20,7 +20,7 @@ import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.LocaleUtils; import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import javax.net.ssl.SSLSession; import java.security.cert.Certificate;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -58,9 +58,9 @@ public abstract class VirtualConnection implements Connection { ...@@ -58,9 +58,9 @@ public abstract class VirtualConnection implements Connection {
return 0; return 0;
} }
public SSLSession getSSLSession() { public Certificate[] getPeerCertificates() {
// Ignore // Ignore
return null; return new Certificate[0];
} }
public boolean isClosed() { public boolean isClosed() {
......
...@@ -21,11 +21,7 @@ import org.jivesoftware.openfire.Connection; ...@@ -21,11 +21,7 @@ import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.ConnectionCloseListener; import org.jivesoftware.openfire.ConnectionCloseListener;
import org.jivesoftware.openfire.PacketDeliverer; import org.jivesoftware.openfire.PacketDeliverer;
import org.jivesoftware.openfire.auth.UnauthorizedException; import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.net.SSLConfig; import org.jivesoftware.openfire.net.*;
import org.jivesoftware.openfire.net.SSLJiveKeyManagerFactory;
import org.jivesoftware.openfire.net.SSLJiveTrustManagerFactory;
import org.jivesoftware.openfire.net.ServerTrustManager;
import org.jivesoftware.openfire.net.ClientTrustManager;
import org.jivesoftware.openfire.session.LocalSession; import org.jivesoftware.openfire.session.LocalSession;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
...@@ -33,15 +29,13 @@ import org.jivesoftware.util.Log; ...@@ -33,15 +29,13 @@ import org.jivesoftware.util.Log;
import org.jivesoftware.util.XMLWriter; import org.jivesoftware.util.XMLWriter;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import javax.net.ssl.KeyManager; import javax.net.ssl.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.cert.Certificate;
/** /**
* Implementation of {@link Connection} inteface specific for NIO connections when using * Implementation of {@link Connection} inteface specific for NIO connections when using
...@@ -137,8 +131,16 @@ public class NIOConnection implements Connection { ...@@ -137,8 +131,16 @@ public class NIOConnection implements Connection {
return ((InetSocketAddress) ioSession.getRemoteAddress()).getAddress().getHostName(); return ((InetSocketAddress) ioSession.getRemoteAddress()).getAddress().getHostName();
} }
public SSLSession getSSLSession() { public Certificate[] getPeerCertificates() {
return (SSLSession) ioSession.getAttribute(SSLFilter.SSL_SESSION); try {
SSLSession sslSession = (SSLSession) ioSession.getAttribute(SSLFilter.SSL_SESSION);
if (sslSession != null) {
return sslSession.getPeerCertificates();
}
} catch (SSLPeerUnverifiedException e) {
Log.warn("Error retrieving client certificates of: " + session, e);
}
return new Certificate[0];
} }
public PacketDeliverer getPacketDeliverer() { public PacketDeliverer getPacketDeliverer() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment