Commit 8c7a56f4 authored by Guus der Kinderen's avatar Guus der Kinderen

Merge pull request #515 from guusdk/OF-1049

OF-1049: Fixes for certificate management
parents da213434 128847a9
...@@ -2262,6 +2262,10 @@ ssl.certificates.store-management.component-stores.info=These stores are used to ...@@ -2262,6 +2262,10 @@ ssl.certificates.store-management.component-stores.info=These stores are used to
ssl.certificates.store-management.connection-manager-stores.title=Connection Manager Stores ssl.certificates.store-management.connection-manager-stores.title=Connection Manager Stores
ssl.certificates.store-management.connection-manager-stores.info=These stores are used to establish connections with Openfire Connection Managers.ssl.certificates.store-management.socket-s2s-stores.title=Server Federation Stores ssl.certificates.store-management.connection-manager-stores.info=These stores are used to establish connections with Openfire Connection Managers.ssl.certificates.store-management.socket-s2s-stores.title=Server Federation Stores
ssl.certificates.store-management.manage=Manage Store Contents ssl.certificates.store-management.manage=Manage Store Contents
ssl.certificates.store-management.file_label=File
ssl.certificates.store-management.password_label=Password
ssl.certificates.store-management.error.cannot-access=Configuration problem: Unable to access the store.
ssl.certificates.store-management.saved_successfully=Settings updated successfully.
# Openfire Certificates Page # Openfire Certificates Page
......
...@@ -142,7 +142,7 @@ public class AdminConsolePlugin implements Plugin { ...@@ -142,7 +142,7 @@ public class AdminConsolePlugin implements Plugin {
sslEnabled = false; sslEnabled = false;
try { try {
final IdentityStore identityStore = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore( ConnectionType.WEBADMIN ); final IdentityStore identityStore = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore( ConnectionType.WEBADMIN );
if (adminSecurePort > 0 ) if (identityStore != null && adminSecurePort > 0 )
{ {
if ( identityStore.getAllCertificates().isEmpty() ) if ( identityStore.getAllCertificates().isEmpty() )
{ {
...@@ -189,7 +189,7 @@ public class AdminConsolePlugin implements Plugin { ...@@ -189,7 +189,7 @@ public class AdminConsolePlugin implements Plugin {
} }
catch ( Exception e ) catch ( Exception e )
{ {
Log.error( "An exception occured while trying to make available the admin console via HTTPS.", e ); Log.error( "An exception occurred while trying to make available the admin console via HTTPS.", e );
} }
// Make sure that at least one connector was registered. // Make sure that at least one connector was registered.
...@@ -206,13 +206,13 @@ public class AdminConsolePlugin implements Plugin { ...@@ -206,13 +206,13 @@ public class AdminConsolePlugin implements Plugin {
try { try {
adminServer.start(); adminServer.start();
// Log the ports that the admin server is listening on.
logAdminConsolePorts();
} }
catch (Exception e) { catch (Exception e) {
Log.error("Could not start admin console server", e); Log.error("Could not start admin console server", e);
} }
// Log the ports that the admin server is listening on.
logAdminConsolePorts();
} }
/** /**
......
...@@ -43,32 +43,34 @@ public class CertificateStoreManager extends BasicModule ...@@ -43,32 +43,34 @@ public class CertificateStoreManager extends BasicModule
{ {
try try
{ {
Log.debug( "(identity store for connection type '{}') Initializing store...", type );
final CertificateStoreConfiguration identityStoreConfiguration = getIdentityStoreConfiguration( type ); final CertificateStoreConfiguration identityStoreConfiguration = getIdentityStoreConfiguration( type );
typeToIdentityStore.put( type, identityStoreConfiguration );
if ( !identityStores.containsKey( identityStoreConfiguration ) ) if ( !identityStores.containsKey( identityStoreConfiguration ) )
{ {
final IdentityStore store = new IdentityStore( identityStoreConfiguration, false ); final IdentityStore store = new IdentityStore( identityStoreConfiguration, false );
identityStores.put( identityStoreConfiguration, store ); identityStores.put( identityStoreConfiguration, store );
} }
typeToIdentityStore.put( type, identityStoreConfiguration );
} }
catch ( CertificateStoreConfigException | IOException e ) catch ( CertificateStoreConfigException | IOException e )
{ {
Log.warn( "Unable to instantiate identity store for type '" + type + "'", e ); Log.warn( "(identity store for connection type '{}') Unable to instantiate store ", type, e );
} }
try try
{ {
Log.debug( "(trust store for connection type '{}') Initializing store...", type );
final CertificateStoreConfiguration trustStoreConfiguration = getTrustStoreConfiguration( type ); final CertificateStoreConfiguration trustStoreConfiguration = getTrustStoreConfiguration( type );
typeToTrustStore.put( type, trustStoreConfiguration );
if ( !trustStores.containsKey( trustStoreConfiguration ) ) if ( !trustStores.containsKey( trustStoreConfiguration ) )
{ {
final TrustStore store = new TrustStore( trustStoreConfiguration, false ); final TrustStore store = new TrustStore( trustStoreConfiguration, false );
trustStores.put( trustStoreConfiguration, store ); trustStores.put( trustStoreConfiguration, store );
} }
typeToTrustStore.put( type, trustStoreConfiguration );
} }
catch ( CertificateStoreConfigException | IOException e ) catch ( CertificateStoreConfigException | IOException e )
{ {
Log.warn( "Unable to instantiate trust store for type '" + type + "'", e ); Log.warn( "(trust store for connection type '{}') Unable to instantiate store ", type, e );
} }
} }
} }
...@@ -86,16 +88,22 @@ public class CertificateStoreManager extends BasicModule ...@@ -86,16 +88,22 @@ public class CertificateStoreManager extends BasicModule
public IdentityStore getIdentityStore( ConnectionType type ) public IdentityStore getIdentityStore( ConnectionType type )
{ {
final CertificateStoreConfiguration configuration = typeToIdentityStore.get( type ); final CertificateStoreConfiguration configuration = typeToIdentityStore.get( type );
if (configuration == null) {
return null;
}
return identityStores.get( configuration ); return identityStores.get( configuration );
} }
public TrustStore getTrustStore( ConnectionType type ) public TrustStore getTrustStore( ConnectionType type )
{ {
final CertificateStoreConfiguration configuration = typeToTrustStore.get( type ); final CertificateStoreConfiguration configuration = typeToTrustStore.get( type );
if (configuration == null) {
return null;
}
return trustStores.get( configuration ); return trustStores.get( configuration );
} }
public void replaceIdentityStore( ConnectionType type, CertificateStoreConfiguration configuration ) throws CertificateStoreConfigException public void replaceIdentityStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
{ {
if ( type == null) if ( type == null)
{ {
...@@ -114,7 +122,7 @@ public class CertificateStoreManager extends BasicModule ...@@ -114,7 +122,7 @@ public class CertificateStoreManager extends BasicModule
if ( !identityStores.containsKey( configuration ) ) if ( !identityStores.containsKey( configuration ) )
{ {
// This constructor can throw an exception. If it does, the state of the manager should not have already changed. // This constructor can throw an exception. If it does, the state of the manager should not have already changed.
final IdentityStore store = new IdentityStore( configuration, true ); final IdentityStore store = new IdentityStore( configuration, createIfAbsent );
identityStores.put( configuration, store ); identityStores.put( configuration, store );
} }
...@@ -143,7 +151,7 @@ public class CertificateStoreManager extends BasicModule ...@@ -143,7 +151,7 @@ public class CertificateStoreManager extends BasicModule
JiveGlobals.setProperty( type.getPrefix() + "keypass", new String( configuration.getPassword() ) ); JiveGlobals.setProperty( type.getPrefix() + "keypass", new String( configuration.getPassword() ) );
} }
public void replaceTrustStore( ConnectionType type, CertificateStoreConfiguration configuration ) throws CertificateStoreConfigException public void replaceTrustStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
{ {
if ( type == null) if ( type == null)
{ {
...@@ -162,7 +170,7 @@ public class CertificateStoreManager extends BasicModule ...@@ -162,7 +170,7 @@ public class CertificateStoreManager extends BasicModule
if ( !trustStores.containsKey( configuration ) ) if ( !trustStores.containsKey( configuration ) )
{ {
// This constructor can throw an exception. If it does, the state of the manager should not have already changed. // This constructor can throw an exception. If it does, the state of the manager should not have already changed.
final TrustStore store = new TrustStore( configuration, true ); final TrustStore store = new TrustStore( configuration, createIfAbsent );
trustStores.put( configuration, store ); trustStores.put( configuration, store );
} }
......
...@@ -7,7 +7,6 @@ import org.jivesoftware.util.JiveGlobals; ...@@ -7,7 +7,6 @@ import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.KeyManagerFactory;
import java.io.IOException; import java.io.IOException;
import java.security.*; import java.security.*;
...@@ -40,26 +39,21 @@ public class IdentityStore extends CertificateStore ...@@ -40,26 +39,21 @@ public class IdentityStore extends CertificateStore
{ {
private static final Logger Log = LoggerFactory.getLogger( IdentityStore.class ); private static final Logger Log = LoggerFactory.getLogger( IdentityStore.class );
// protected final KeyManagerFactory keyFactory;
public IdentityStore( CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException public IdentityStore( CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
{ {
super( configuration, createIfAbsent ); super( configuration, createIfAbsent );
// try
// {
// keyFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
// keyFactory.init( store, configuration.getPassword() );
// }
// catch ( UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException ex )
// {
// throw new CertificateStoreConfigException( "Unable to load store of type '" + configuration.getType() + "' from location '" + configuration.getFile() + "'", ex );
// }
}
// public KeyManager[] getKeyManagers() try
// { {
// return keyFactory.getKeyManagers(); final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );
// } keyManagerFactory.init( this.getStore(), configuration.getPassword() );
}
catch ( NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException ex )
{
throw new CertificateStoreConfigException( "Unable to initialize identity store (a common cause: the password for a key is different from the password of the entire store).", ex );
}
}
/** /**
* Creates a Certificate Signing Request based on the private key and certificate identified by the provided alias. * Creates a Certificate Signing Request based on the private key and certificate identified by the provided alias.
......
...@@ -3,6 +3,10 @@ ...@@ -3,6 +3,10 @@
<%@ page import="java.util.HashMap" %> <%@ page import="java.util.HashMap" %>
<%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %> <%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %> <%@ page import="org.jivesoftware.openfire.XMPPServer" %>
<%@ page import="org.jivesoftware.openfire.keystore.CertificateStoreManager" %>
<%@ page import="org.jivesoftware.openfire.keystore.CertificateStoreConfiguration" %>
<%@ page import="java.io.File" %>
<%@ page import="org.jivesoftware.util.Log" %>
<%@ taglib uri="admin" prefix="admin" %> <%@ taglib uri="admin" prefix="admin" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
...@@ -12,10 +16,55 @@ ...@@ -12,10 +16,55 @@
<jsp:useBean id="now" class="java.util.Date"/> <jsp:useBean id="now" class="java.util.Date"/>
<% webManager.init(request, response, session, application, out ); <% webManager.init(request, response, session, application, out );
final CertificateStoreManager certificateStoreManager = XMPPServer.getInstance().getCertificateStoreManager();
final Map<String, String> errors = new HashMap<>(); final Map<String, String> errors = new HashMap<>();
pageContext.setAttribute( "errors", errors ); pageContext.setAttribute( "errors", errors );
pageContext.setAttribute( "connectionTypes", ConnectionType.values() ); pageContext.setAttribute( "connectionTypes", ConnectionType.values() );
pageContext.setAttribute( "certificateStoreManager", XMPPServer.getInstance().getCertificateStoreManager() ); pageContext.setAttribute( "certificateStoreManager", certificateStoreManager );
final boolean update = request.getParameter("update") != null;
if ( update ) {
ConnectionType connectionType = null;
try {
connectionType = ConnectionType.valueOf( request.getParameter( "connectionType" ) );
} catch ( IllegalArgumentException ex ) {
Log.warn( ex );
errors.put( "connectionType", ex.getMessage() );
}
final String locKey = request.getParameter( "loc-key" );
final String pwdKey = request.getParameter( "pwd-key" );
final String locTrust = request.getParameter( "loc-trust" );
final String pwdTrust = request.getParameter( "pwd-trust" );
if ( locKey == null || locKey.isEmpty() ) {
errors.put( "locKey", "Identity Store location must be defined." );
}
if ( pwdKey == null || pwdKey.isEmpty() ) {
errors.put( "pwdKey", "Identity Store password must be defined." );
}
if ( locTrust == null || locTrust.isEmpty() ) {
errors.put( "locTrust", "Trust Store location must be defined." );
}
if ( pwdTrust == null || pwdTrust.isEmpty() ) {
errors.put( "pwdTrust", "Trust Store password must be defined." );
}
if ( errors.isEmpty() ) {
try
{
final CertificateStoreConfiguration configKey = new CertificateStoreConfiguration( "jks", new File( locKey ), pwdKey.toCharArray() );
final CertificateStoreConfiguration configTrust = new CertificateStoreConfiguration( "jks", new File( locTrust ), pwdTrust.toCharArray() );
certificateStoreManager.replaceIdentityStore( connectionType, configKey, false );
certificateStoreManager.replaceTrustStore( connectionType, configTrust, false );
pageContext.setAttribute( "updated", true );
} catch ( Exception ex ) {
Log.warn( ex );
errors.put( "update", ex.getMessage() );
}
}
}
%> %>
<html> <html>
<head> <head>
...@@ -40,6 +89,13 @@ ...@@ -40,6 +89,13 @@
</admin:infobox> </admin:infobox>
</c:forEach> </c:forEach>
<!-- Display success report, but only if there were no errors. -->
<c:if test="${updated and empty errors}">
<admin:infoBox type="success">
<fmt:message key="ssl.certificates.store-management.saved_successfully"/>
</admin:infoBox>
</c:if>
<p> <p>
<fmt:message key="ssl.certificates.store-management.info-1"/> <fmt:message key="ssl.certificates.store-management.info-1"/>
</p> </p>
...@@ -73,27 +129,77 @@ ...@@ -73,27 +129,77 @@
</c:choose> </c:choose>
</c:set> </c:set>
<admin:contentBox title="${title}"> <form action="security-certificate-store-management.jsp" method="post">
<p> <input type="hidden" name="connectionType" value="${connectionType}"/>
<c:out value="${description}"/>
</p> <admin:contentBox title="${title}">
<p>
<table cellpadding="0" cellspacing="0" border="0"> <c:out value="${description}"/>
<tbody> </p>
<tr>
<td><label for="loc-key-socket"><fmt:message key="ssl.certificates.identity-store"/>:</label></td> <h4><fmt:message key="ssl.certificates.identity-store"/></h4>
<td><input id="loc-key-socket" name="loc-key-socket" type="text" size="80" readonly value="${certificateStoreManager.getIdentityStore(connectionType).configuration.file}"/></td>
<td><a href="security-keystore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td> <c:if test="${empty certificateStoreManager.getIdentityStore(connectionType)}">
</tr> <admin:infobox type="warning"><fmt:message key="ssl.certificates.store-management.error.cannot-access"/></admin:infobox>
<tr> </c:if>
<td><label for="loc-trust-socket-c2s"><fmt:message key="ssl.certificates.trust-store"/>:</label></td>
<td><input id="loc-trust-socket-c2s" name="loc-trust-socket-c2s" type="text" size="80" readonly value="${certificateStoreManager.getTrustStore(connectionType).configuration.file}"/></td> <c:set var="pwdKey" value=""/>
<td><a href="security-truststore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td> <c:forEach items="${certificateStoreManager.getIdentityStoreConfiguration(connectionType).password}" var="c">
</tr> <c:set var="pwdKey" value="${pwdKey}${c}"/>
</tbody> </c:forEach>
</table>
<table cellpadding="0" cellspacing="0" border="0">
</admin:contentBox> <tbody>
<tr>
<td><label for="loc-key"><fmt:message key="ssl.certificates.store-management.file_label"/>:</label></td>
<td><input id="loc-key" name="loc-key" type="text" size="80" value="${certificateStoreManager.getIdentityStoreConfiguration(connectionType).file}"/></td>
</tr>
<tr>
<td><label for="pwd-key"><fmt:message key="ssl.certificates.store-management.password_label"/>:</label></td>
<td><input id="pwd-key" name="pwd-key" type="password" size="30" value="${pwdKey}"/></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><a href="security-keystore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td>
</tr>
</tbody>
</table>
<br/>
<h4><fmt:message key="ssl.certificates.trust-store"/></h4>
<c:if test="${empty certificateStoreManager.getTrustStore(connectionType)}">
<admin:infobox type="warning"><fmt:message key="ssl.certificates.store-management.error.cannot-access"/></admin:infobox>
</c:if>
<c:set var="pwdTrust" value=""/>
<c:forEach items="${certificateStoreManager.getTrustStoreConfiguration(connectionType).password}" var="c">
<c:set var="pwdTrust" value="${pwdTrust}${c}"/>
</c:forEach>
<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td><label for="loc-trust"><fmt:message key="ssl.certificates.store-management.file_label"/>:</label></td>
<td><input id="loc-trust" name="loc-trust" type="text" size="80" value="${certificateStoreManager.getTrustStoreConfiguration(connectionType).file}"/></td>
</tr>
<tr>
<td><label for="pwd-trust"><fmt:message key="ssl.certificates.store-management.password_label"/>:</label></td>
<td><input id="pwd-trust" name="pwd-trust" type="password" size="30" value="${pwdTrust}"/></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><a href="security-truststore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td>
</tr>
</tbody>
</table>
<br/>
<input type="submit" name="update" value="<fmt:message key="global.save_settings" />">
</admin:contentBox>
</form>
</c:forEach> </c:forEach>
......
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