Skip to content

Commit

Permalink
0001052: Install a default ssl cert if none exists when ssl is turned…
Browse files Browse the repository at this point in the history
… on so that ssl works by default
  • Loading branch information
chenson42 committed Jun 4, 2013
1 parent 0c93d9d commit d521147
Show file tree
Hide file tree
Showing 20 changed files with 192 additions and 50 deletions.
Expand Up @@ -27,6 +27,7 @@

import org.jumpmind.db.platform.IDatabasePlatform;
import org.jumpmind.properties.TypedProperties;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.AbstractSymmetricEngine;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.ITypedPropertiesFactory;
Expand Down Expand Up @@ -74,6 +75,11 @@ public AndroidSymmetricEngine(String registrationUrl, String externalId, String
this.androidContext = androidContext;
init();
}

@Override
protected SecurityServiceType getSecurityServiceType() {
return SecurityServiceType.CLIENT;
}

@Override
protected ITypedPropertiesFactory createTypedPropertiesFactory() {
Expand Down
Expand Up @@ -53,6 +53,7 @@
import org.jumpmind.exception.IoException;
import org.jumpmind.properties.TypedProperties;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.common.SystemConstants;
import org.jumpmind.symmetric.common.TableConstants;
Expand Down Expand Up @@ -155,6 +156,11 @@ public ClientSymmetricEngine() {
public ClientSymmetricEngine(boolean registerEngine) {
this((Properties) null, registerEngine);
}

@Override
protected SecurityServiceType getSecurityServiceType() {
return SecurityServiceType.CLIENT;
}

@Override
protected void init() {
Expand Down Expand Up @@ -207,7 +213,7 @@ public synchronized void stop() {

public static BasicDataSource createBasicDataSource(File propsFile) {
TypedProperties properties = createTypedPropertiesFactory(propsFile, null).reload();
return BasicDataSourceFactory.create(properties, SecurityServiceFactory.create(properties));
return BasicDataSourceFactory.create(properties, SecurityServiceFactory.create(SecurityServiceType.CLIENT, properties));
}

@Override
Expand All @@ -226,7 +232,7 @@ public static IDatabasePlatform createDatabasePlatform(TypedProperties propertie
if (dataSource == null) {
String jndiName = properties.getProperty(ParameterConstants.DB_JNDI_NAME);
if (StringUtils.isBlank(jndiName)) {
dataSource = BasicDataSourceFactory.create(properties, SecurityServiceFactory.create(properties));
dataSource = BasicDataSourceFactory.create(properties, SecurityServiceFactory.create(SecurityServiceType.CLIENT, properties));
} else {
try {
log.info("Looking up datasource in jndi. The jndi name is {}", jndiName);
Expand Down
Expand Up @@ -45,6 +45,7 @@
import org.jumpmind.properties.TypedProperties;
import org.jumpmind.security.ISecurityService;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.common.Constants;
import org.jumpmind.symmetric.common.ParameterConstants;
import org.jumpmind.symmetric.common.TableConstants;
Expand Down Expand Up @@ -243,10 +244,12 @@ public static ISymmetricEngine findEngineByName(String name) {
public void setDeploymentType(String deploymentType) {
this.deploymentType = deploymentType;
}

protected abstract SecurityServiceType getSecurityServiceType();

protected void init() {
this.propertiesFactory = createTypedPropertiesFactory();
this.securityService = SecurityServiceFactory.create(propertiesFactory.reload());
this.securityService = SecurityServiceFactory.create(getSecurityServiceType(), propertiesFactory.reload());
TypedProperties properties = this.propertiesFactory.reload();
this.platform = createDatabasePlatform(properties);
this.parameterService = new ParameterService(platform, propertiesFactory, properties.get(
Expand Down
Expand Up @@ -20,6 +20,8 @@
*/
package org.jumpmind.symmetric.common;

import org.jumpmind.security.SecurityConstants;

/**
* These are properties that can be set only as Java System properties using
* -D settings.
Expand All @@ -37,7 +39,7 @@ public class SystemConstants {
public static final String SYSPROP_DEFAULT_HTTP_PORT = "symmetric.default.http.port";
public static final String SYSPROP_DEFAULT_HTTPS_PORT = "symmetric.default.https.port";
public static final String SYSPROP_DEFAULT_JMX_PORT = "symmetric.default.jmx.port";
public static final String SYSPROP_KEYSTORE_TYPE = "sym.keystore.type";
public static final String SYSPROP_KEYSTORE_CERT_ALIAS = "sym.keystore.ssl.cert.alias";
public static final String SYSPROP_KEYSTORE_TYPE = SecurityConstants.SYSPROP_KEYSTORE_TYPE;
public static final String SYSPROP_KEYSTORE_CERT_ALIAS = SecurityConstants.SYSPROP_KEYSTORE_CERT_ALIAS;

}
Expand Up @@ -32,13 +32,14 @@
import org.jumpmind.security.ISecurityService;
import org.jumpmind.security.SecurityConstants;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.slf4j.LoggerFactory;

public class BasicDataSourceFactory {


public static BasicDataSource create(TypedProperties properties) {
return create(properties, SecurityServiceFactory.create(properties));
return create(properties, SecurityServiceFactory.create(SecurityServiceType.CLIENT, properties));
}

public static BasicDataSource create(TypedProperties properties,
Expand Down
5 changes: 5 additions & 0 deletions symmetric-parent/pom.xml
Expand Up @@ -587,6 +587,11 @@
<artifactId>ant</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>140</version>
</dependency>
<!-- Commons -->
<dependency>
<groupId>commons-io</groupId>
Expand Down
Binary file modified symmetric-server/src/main/deploy/security/keystore
Binary file not shown.
Expand Up @@ -27,7 +27,7 @@
import org.slf4j.MDC;

/**
* Launch the SymmetricDS engine as a standalone client or server.
* Launch the SymmetricDS engine as a stand alone client or server.
*/
public class SymmetricLauncher extends AbstractCommandLauncher {

Expand Down
Expand Up @@ -52,7 +52,10 @@
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.WebAppContext;
import org.jumpmind.properties.TypedProperties;
import org.jumpmind.security.ISecurityService;
import org.jumpmind.security.SecurityConstants;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.common.ServerConstants;
import org.jumpmind.symmetric.common.SystemConstants;
import org.jumpmind.symmetric.web.ServletUtils;
Expand Down Expand Up @@ -359,6 +362,8 @@ protected Connector[] getConnectors(int port, int securePort, Mode mode) {
log.info("About to start {} web server on port {}", name, port);
}
if (mode.equals(Mode.HTTPS) || mode.equals(Mode.MIXED)) {
ISecurityService securityService = SecurityServiceFactory.create(SecurityServiceType.SERVER, new TypedProperties(System.getProperties()));
securityService.installDefaultSslCert(host);
Connector connector = new SslSocketConnector();
String keyStorePassword = System
.getProperty(SecurityConstants.SYSPROP_KEYSTORE_PASSWORD);
Expand Down
Expand Up @@ -20,28 +20,27 @@
*/
package org.jumpmind.symmetric.web;

import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.symmetric.io.IoConstants;
import org.jumpmind.symmetric.model.ChannelMap;
import org.jumpmind.symmetric.model.NodeSecurity;
import org.jumpmind.symmetric.model.ProcessInfo;
import org.jumpmind.symmetric.model.ProcessInfo.Status;
import org.jumpmind.symmetric.model.ProcessInfoKey;
import org.jumpmind.symmetric.model.ProcessInfoKey.ProcessType;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IDataExtractorService;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.service.IRegistrationService;
import org.jumpmind.symmetric.statistic.IStatisticManager;
import org.jumpmind.symmetric.transport.IOutgoingTransport;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.symmetric.model.ChannelMap;
import org.jumpmind.symmetric.model.NodeSecurity;
import org.jumpmind.symmetric.model.ProcessInfo;
import org.jumpmind.symmetric.model.ProcessInfo.Status;
import org.jumpmind.symmetric.model.ProcessInfoKey;
import org.jumpmind.symmetric.model.ProcessInfoKey.ProcessType;
import org.jumpmind.symmetric.service.IConfigurationService;
import org.jumpmind.symmetric.service.IDataExtractorService;
import org.jumpmind.symmetric.service.INodeService;
import org.jumpmind.symmetric.service.IParameterService;
import org.jumpmind.symmetric.service.IRegistrationService;
import org.jumpmind.symmetric.statistic.IStatisticManager;
import org.jumpmind.symmetric.transport.IOutgoingTransport;

/**
* Handles data pulls from other nodes.
Expand Down
Expand Up @@ -24,6 +24,7 @@
import java.util.ArrayList;
import java.util.List;

import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.ClientSymmetricEngine;
import org.jumpmind.symmetric.common.ParameterConstants;

Expand All @@ -34,6 +35,11 @@ public class ServerSymmetricEngine extends ClientSymmetricEngine {
public ServerSymmetricEngine(File propertiesFile) {
super(propertiesFile);
}

@Override
protected SecurityServiceType getSecurityServiceType() {
return SecurityServiceType.SERVER;
}

@Override
protected void init() {
Expand Down
Expand Up @@ -40,6 +40,7 @@
import org.jumpmind.security.ISecurityService;
import org.jumpmind.security.SecurityConstants;
import org.jumpmind.security.SecurityServiceFactory;
import org.jumpmind.security.SecurityServiceFactory.SecurityServiceType;
import org.jumpmind.symmetric.AbstractCommandLauncher;
import org.jumpmind.symmetric.ISymmetricEngine;
import org.jumpmind.symmetric.common.ParameterConstants;
Expand Down Expand Up @@ -193,7 +194,7 @@ public ISymmetricEngine install(Properties passedInProperties) throws Exception
String password = properties.getProperty(BasicDataSourcePropertyConstants.DB_POOL_PASSWORD);
if (StringUtils.isNotBlank(password) && !password.startsWith(SecurityConstants.PREFIX_ENC)) {
try {
ISecurityService service = SecurityServiceFactory.create(properties);
ISecurityService service = SecurityServiceFactory.create(SecurityServiceType.CLIENT, properties);
properties.setProperty(BasicDataSourcePropertyConstants.DB_POOL_PASSWORD,
SecurityConstants.PREFIX_ENC + service.encrypt(password));
} catch (Exception ex) {
Expand Down
6 changes: 6 additions & 0 deletions symmetric-util/pom.xml
Expand Up @@ -47,6 +47,12 @@
<artifactId>log4j</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
@@ -0,0 +1,85 @@
package org.jumpmind.security;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.security.auth.x500.X500Principal;

import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.jumpmind.util.AppUtils;

public class BouncyCastleSecurityService extends SecurityService {

public KeyPair generateRSAKeyPair() throws Exception {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(1024, new SecureRandom());
return kpGen.generateKeyPair();
}

public X509Certificate generateV1Certificate(String host, KeyPair pair) throws Exception {

host = host == null ? AppUtils.getHostName() : host;
String certString = String.format(
"CN=%s, OU=SymmetricDS, O=JumpMind, L=Unknown, ST=Unknown, C=Unknown", host);
log.info("Installing a default SSL certificate: {}", certString);

X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();

certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(new X500Principal(certString));
certGen.setNotBefore(new Date(System.currentTimeMillis() - 86400000));
certGen.setNotAfter(new Date(System.currentTimeMillis() + 788400000000l));
certGen.setSubjectDN(new X500Principal(certString));
certGen.setPublicKey(pair.getPublic());
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");

return certGen.generate(pair.getPrivate(), "BC");
}

public PKCS10CertificationRequest generateRequest(KeyPair pair) throws Exception {
return new PKCS10CertificationRequest("SHA256withRSA", new X500Principal(
"CN=Requested Test Certificate"), pair.getPublic(), null, pair.getPrivate());
}

@Override
public void installDefaultSslCert(String host) {
synchronized (BouncyCastleSecurityService.class) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

try {
KeyStore keyStore = getKeyStore(getKeyStorePassword());
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(
getKeyStorePassword().toCharArray());
String alias = System.getProperty(SecurityConstants.SYSPROP_KEYSTORE_CERT_ALIAS,
SecurityConstants.ALIAS_SYM_PRIVATE_KEY);
Entry entry = keyStore.getEntry(alias, param);
if (entry == null) {
KeyPair pair = generateRSAKeyPair();
X509Certificate cert = generateV1Certificate(host, pair);

X509Certificate[] serverChain = new X509Certificate[] { cert };

keyStore.setEntry(alias, new KeyStore.PrivateKeyEntry(pair.getPrivate(),
serverChain), param);

saveKeyStore(keyStore, getKeyStorePassword());
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}

}

}

}
Expand Up @@ -28,6 +28,8 @@ public interface ISecurityService {

public void init();

public void installDefaultSslCert(String host);

public String nextSecureHexString(int len);

public String encrypt(String plainText);
Expand Down
Expand Up @@ -22,6 +22,14 @@

public class SecurityConstants {

public static final String SYSPROP_KEYSTORE_TYPE = "sym.keystore.type";

public static final String SYSPROP_KEYSTORE_CERT_ALIAS = "sym.keystore.ssl.cert.alias";

public static final String SYSPROP_KEYSTORE = "sym.keystore.file";

public static final String SYSPROP_KEYSTORE_PASSWORD = "javax.net.ssl.keyStorePassword";

public final static String CLASS_NAME_SECURITY_SERVICE = "security.service.class.name";

public static final String PREFIX_ENC = "enc:";
Expand All @@ -44,9 +52,5 @@ public class SecurityConstants {
public static final String ALIAS_SYM_SECRET_KEY = "sym.secret";

public static final String EMBEDDED_WEBSERVER_DEFAULT_ROLE="symmetric";

public static final String SYSPROP_KEYSTORE = "sym.keystore.file";

public static final String SYSPROP_KEYSTORE_PASSWORD = "javax.net.ssl.keyStorePassword";

}

0 comments on commit d521147

Please sign in to comment.