Skip to content

Commit

Permalink
Merge pull request #515 from guusdk/OF-1049
Browse files Browse the repository at this point in the history
OF-1049: Fixes for certificate management
  • Loading branch information
guusdk committed Jan 25, 2016
2 parents da21343 + 128847a commit 8c7a56f
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 52 deletions.
4 changes: 4 additions & 0 deletions src/i18n/openfire_i18n_en.properties
Expand Up @@ -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.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.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

Expand Down
Expand Up @@ -142,7 +142,7 @@ public void startup() {
sslEnabled = false;
try {
final IdentityStore identityStore = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore( ConnectionType.WEBADMIN );
if (adminSecurePort > 0 )
if (identityStore != null && adminSecurePort > 0 )
{
if ( identityStore.getAllCertificates().isEmpty() )
{
Expand Down Expand Up @@ -189,7 +189,7 @@ public void startup() {
}
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.
Expand All @@ -206,13 +206,13 @@ public void startup() {

try {
adminServer.start();

// Log the ports that the admin server is listening on.
logAdminConsolePorts();
}
catch (Exception e) {
Log.error("Could not start admin console server", e);
}

// Log the ports that the admin server is listening on.
logAdminConsolePorts();
}

/**
Expand Down
Expand Up @@ -43,32 +43,34 @@ public synchronized void initialize( XMPPServer server )
{
try
{
Log.debug( "(identity store for connection type '{}') Initializing store...", type );
final CertificateStoreConfiguration identityStoreConfiguration = getIdentityStoreConfiguration( type );
typeToIdentityStore.put( type, identityStoreConfiguration );
if ( !identityStores.containsKey( identityStoreConfiguration ) )
{
final IdentityStore store = new IdentityStore( identityStoreConfiguration, false );
identityStores.put( identityStoreConfiguration, store );
}
typeToIdentityStore.put( type, identityStoreConfiguration );
}
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
{
Log.debug( "(trust store for connection type '{}') Initializing store...", type );
final CertificateStoreConfiguration trustStoreConfiguration = getTrustStoreConfiguration( type );
typeToTrustStore.put( type, trustStoreConfiguration );
if ( !trustStores.containsKey( trustStoreConfiguration ) )
{
final TrustStore store = new TrustStore( trustStoreConfiguration, false );
trustStores.put( trustStoreConfiguration, store );
}
typeToTrustStore.put( type, trustStoreConfiguration );
}
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 );
}
}
}
Expand All @@ -86,16 +88,22 @@ public synchronized void destroy()
public IdentityStore getIdentityStore( ConnectionType type )
{
final CertificateStoreConfiguration configuration = typeToIdentityStore.get( type );
if (configuration == null) {
return null;
}
return identityStores.get( configuration );
}

public TrustStore getTrustStore( ConnectionType type )
{
final CertificateStoreConfiguration configuration = typeToTrustStore.get( type );
if (configuration == null) {
return null;
}
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)
{
Expand All @@ -114,7 +122,7 @@ public void replaceIdentityStore( ConnectionType type, CertificateStoreConfigura
if ( !identityStores.containsKey( configuration ) )
{
// 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 );
}

Expand Down Expand Up @@ -143,7 +151,7 @@ public void replaceIdentityStore( ConnectionType type, CertificateStoreConfigura
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)
{
Expand All @@ -162,7 +170,7 @@ public void replaceTrustStore( ConnectionType type, CertificateStoreConfiguratio
if ( !trustStores.containsKey( configuration ) )
{
// 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 );
}

Expand Down
28 changes: 11 additions & 17 deletions src/java/org/jivesoftware/openfire/keystore/IdentityStore.java
Expand Up @@ -7,7 +7,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import java.io.IOException;
import java.security.*;
Expand Down Expand Up @@ -40,26 +39,21 @@ public class IdentityStore extends CertificateStore
{
private static final Logger Log = LoggerFactory.getLogger( IdentityStore.class );

// protected final KeyManagerFactory keyFactory;

public IdentityStore( CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
{
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()
// {
// return keyFactory.getKeyManagers();
// }
try
{
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.
Expand Down
150 changes: 128 additions & 22 deletions src/web/security-certificate-store-management.jsp
Expand Up @@ -3,6 +3,10 @@
<%@ page import="java.util.HashMap" %>
<%@ page import="org.jivesoftware.openfire.spi.ConnectionType" %>
<%@ 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="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
Expand All @@ -12,10 +16,55 @@
<jsp:useBean id="now" class="java.util.Date"/>
<% webManager.init(request, response, session, application, out );
final CertificateStoreManager certificateStoreManager = XMPPServer.getInstance().getCertificateStoreManager();
final Map<String, String> errors = new HashMap<>();
pageContext.setAttribute( "errors", errors );
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>
<head>
Expand All @@ -40,6 +89,13 @@
</admin:infobox>
</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>
<fmt:message key="ssl.certificates.store-management.info-1"/>
</p>
Expand Down Expand Up @@ -73,27 +129,77 @@
</c:choose>
</c:set>

<admin:contentBox title="${title}">
<p>
<c:out value="${description}"/>
</p>

<table cellpadding="0" cellspacing="0" border="0">
<tbody>
<tr>
<td><label for="loc-key-socket"><fmt:message key="ssl.certificates.identity-store"/>:</label></td>
<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>
</tr>
<tr>
<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>
<td><a href="security-truststore.jsp?connectionType=${connectionType}"><fmt:message key="ssl.certificates.store-management.manage"/></a></td>
</tr>
</tbody>
</table>

</admin:contentBox>
<form action="security-certificate-store-management.jsp" method="post">
<input type="hidden" name="connectionType" value="${connectionType}"/>

<admin:contentBox title="${title}">
<p>
<c:out value="${description}"/>
</p>

<h4><fmt:message key="ssl.certificates.identity-store"/></h4>

<c:if test="${empty certificateStoreManager.getIdentityStore(connectionType)}">
<admin:infobox type="warning"><fmt:message key="ssl.certificates.store-management.error.cannot-access"/></admin:infobox>
</c:if>

<c:set var="pwdKey" value=""/>
<c:forEach items="${certificateStoreManager.getIdentityStoreConfiguration(connectionType).password}" var="c">
<c:set var="pwdKey" value="${pwdKey}${c}"/>
</c:forEach>

<table cellpadding="0" cellspacing="0" border="0">
<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>

Expand Down

0 comments on commit 8c7a56f

Please sign in to comment.