Commit d0f3851d authored by Dele Olajide's avatar Dele Olajide

Merge pull request #59 from surevine/dwd/s2s-external-178

More S2S fixes
parents b1dfb9c1 dc21027b
......@@ -391,12 +391,12 @@ public class SessionManager extends BasicModule implements ClusterEventListener
* @return the newly created {@link IncomingServerSession}.
* @throws UnauthorizedException if the local server has not been initialized yet.
*/
public LocalIncomingServerSession createIncomingServerSession(Connection conn, StreamID id)
public LocalIncomingServerSession createIncomingServerSession(Connection conn, StreamID id, String fromDomain)
throws UnauthorizedException {
if (serverName == null) {
throw new UnauthorizedException("Server not initialized");
}
LocalIncomingServerSession session = new LocalIncomingServerSession(serverName, conn, id);
LocalIncomingServerSession session = new LocalIncomingServerSession(serverName, conn, id, fromDomain);
conn.init(session);
// Register to receive close notification on this session so we can
// remove its route from the sessions set
......
......@@ -193,13 +193,17 @@ public class SASLAuthentication {
Element mechs = DocumentHelper.createElement(new QName("mechanisms",
new Namespace("", "urn:ietf:params:xml:ns:xmpp-sasl")));
if (session instanceof IncomingServerSession) {
if (session instanceof LocalIncomingServerSession) {
// Server connections don't follow the same rules as clients
if (session.isSecure()) {
boolean haveTrustedCertificate = false;
try {
X509Certificate trusted = CertificateManager.getEndEntityCertificate(((LocalSession)session).getConnection().getPeerCertificates(), SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
LocalIncomingServerSession svr = (LocalIncomingServerSession)session;
X509Certificate trusted = CertificateManager.getEndEntityCertificate(svr.getConnection().getPeerCertificates(), SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
haveTrustedCertificate = trusted != null;
if (trusted != null && svr.getDefaultIdentity() != null) {
haveTrustedCertificate = verifyCertificate(trusted, svr.getDefaultIdentity());
}
} catch (IOException ex) {
Log.warn("Exception occurred while trying to determine whether remote certificate is trusted. Treating as untrusted.", ex);
}
......@@ -520,6 +524,28 @@ public class SASLAuthentication {
}
hostname = new String(StringUtils.decodeBase64(hostname), CHARSET);
if (hostname.length() == 0) {
hostname = null;
}
try {
LocalIncomingServerSession svr = (LocalIncomingServerSession)session;
String defHostname = svr.getDefaultIdentity();
if (hostname == null) {
hostname = defHostname;
} else if (!hostname.equals(defHostname)) {
// Mismatch; really odd.
Log.info("SASLAuthentication rejected from='{}' and authzid='{}'", hostname, defHostname);
authenticationFailed(session, Failure.NOT_AUTHORIZED);
return Status.failed;
}
} catch(Exception e) {
// Erm. Nothing?
}
if (hostname == null) {
Log.info("No authzid supplied for anonymous session.");
authenticationFailed(session, Failure.NOT_AUTHORIZED);
return Status.failed;
}
// Check if certificate validation is disabled for s2s
// Flag that indicates if certificates of the remote server should be validated.
// Disabling certificate validation is not recommended for production environments.
......@@ -552,9 +578,18 @@ public class SASLAuthentication {
return Status.failed;
}
for (Certificate certificate : connection.getPeerCertificates()) {
principals.addAll(CertificateManager.getPeerIdentities((X509Certificate)certificate));
X509Certificate trusted;
try {
trusted = CertificateManager.getEndEntityCertificate(connection.getPeerCertificates(), SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
} catch (IOException e) {
trusted = null;
}
if (trusted == null) {
Log.debug("SASLAuthentication: EXTERNAL authentication requested, but EE cert untrusted.");
authenticationFailed(session, Failure.NOT_AUTHORIZED);
return Status.failed;
}
principals.addAll(CertificateManager.getPeerIdentities((X509Certificate)trusted));
if(principals.size() == 1) {
principal = principals.get(0);
......@@ -603,12 +638,8 @@ public class SASLAuthentication {
return Status.failed;
}
public static boolean verifyCertificates(Certificate[] chain, String hostname) {
try {
X509Certificate trusted = CertificateManager.getEndEntityCertificate(chain, SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
if (trusted != null) {
for (String identity : CertificateManager.getPeerIdentities(trusted)) {
public static boolean verifyCertificate(X509Certificate trustedCert, String hostname) {
for (String identity : CertificateManager.getPeerIdentities(trustedCert)) {
// Verify that either the identity is the same as the hostname, or for wildcarded
// identities that the hostname ends with .domainspecified or -is- domainspecified.
if ((identity.startsWith("*.")
......@@ -618,6 +649,15 @@ public class SASLAuthentication {
return true;
}
}
return false;
}
public static boolean verifyCertificates(Certificate[] chain, String hostname) {
try {
X509Certificate trusted = CertificateManager.getEndEntityCertificate(chain, SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
if (trusted != null) {
return verifyCertificate(trusted, hostname);
}
} catch(IOException e) {
Log.warn("Keystore issue while verifying certificate chain: {}", e.getMessage());
......
......@@ -431,7 +431,7 @@ public class ServerDialback {
Log.debug("ServerDialback: RS - Validation of remote domain for incoming session from {} to {} was successful.", hostname, recipient);
// Create a server Session for the remote server
LocalIncomingServerSession session = sessionManager.
createIncomingServerSession(connection, streamID);
createIncomingServerSession(connection, streamID, hostname);
// Add the validated domain as a valid domain
session.addValidatedDomain(hostname);
// Set the domain or subdomain of the local server used when
......
......@@ -86,6 +86,11 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
*/
private String localDomain = null;
/**
* Default domain, as supplied in stream header typically.
*/
private String fromDomain = null;
/**
* Creates a new session that will receive packets. The new session will be authenticated
* before being returned. If the authentication process fails then the answer will be
......@@ -105,6 +110,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
XmlPullParser xpp = reader.getXPPParser();
String version = xpp.getAttributeValue("", "version");
String fromDomain = xpp.getAttributeValue("", "from");
int[] serverVersion = version != null ? decodeVersion(version) : new int[] {0,0};
try {
......@@ -112,7 +118,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
StreamID streamID = SessionManager.getInstance().nextStreamID();
// Create a server Session for the remote server
LocalIncomingServerSession session =
SessionManager.getInstance().createIncomingServerSession(connection, streamID);
SessionManager.getInstance().createIncomingServerSession(connection, streamID, fromDomain);
// Send the stream header
StringBuilder openingStream = new StringBuilder();
......@@ -121,6 +127,9 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\"");
openingStream.append(" from=\"").append(serverName).append("\"");
if (fromDomain != null) {
openingStream.append(" to=\"").append(fromDomain).append("\"");
}
openingStream.append(" id=\"").append(streamID).append("\"");
// OF-443: Not responding with a 1.0 version in the stream header when federating with older
......@@ -184,7 +193,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
if (ServerDialback.isEnabled()) {
// Also offer server dialback (when TLS is not required). Server dialback may be offered
// after TLS has been negotiated and a self-signed certificate is being used
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"/>");
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"><errors/></dialback>");
}
sb.append("</stream:features>");
......@@ -204,8 +213,13 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
}
public LocalIncomingServerSession(String serverName, Connection connection, StreamID streamID) {
public LocalIncomingServerSession(String serverName, Connection connection, StreamID streamID, String fromDomain) {
super(serverName, connection, streamID);
this.fromDomain = fromDomain;
}
public String getDefaultIdentity() {
return this.fromDomain;
}
@Override
......@@ -255,7 +269,7 @@ public class LocalIncomingServerSession extends LocalServerSession implements In
public boolean isValidDomain(String domain) {
// Check if the specified domain is contained in any of the validated domains
for (String validatedDomain : getValidatedDomains()) {
if (domain.contains(validatedDomain)) {
if (domain.equals(validatedDomain)) {
return true;
}
}
......
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