<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" name="Jetty Service Factory">
- <implementation class="org.argeo.cms.servlet.internal.jetty.JettyServiceFactory"/>
- <service>
- <provide interface="org.osgi.service.cm.ManagedServiceFactory"/>
- </service>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" activate="start" deactivate="stop" name="Jetty Service Factory">
+ <implementation class="org.argeo.cms.servlet.internal.jetty.JettyConfig"/>
<property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
+ <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
</scr:component>
protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
// anonymous
+ ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
try {
+ Thread.currentThread().setContextClassLoader(CmsServletContext.class.getClassLoader());
LoginContext lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS,
new RemoteAuthCallbackHandler(new ServletHttpRequest(request), new ServletHttpResponse(response)));
lc.login();
if (log.isDebugEnabled())
log.error("Cannot log in as anonymous", e1);
return null;
+ } finally {
+ Thread.currentThread().setContextClassLoader(currentContextClassLoader);
}
}
--- /dev/null
+package org.argeo.cms.servlet.internal.jetty;
+
+/** Compatible with Jetty. */
+public interface InternalHttpConstants {
+ static final String HTTP_ENABLED = "http.enabled";
+ static final String HTTP_PORT = "http.port";
+ static final String HTTP_HOST = "http.host";
+ static final String HTTPS_ENABLED = "https.enabled";
+ static final String HTTPS_HOST = "https.host";
+ static final String HTTPS_PORT = "https.port";
+ static final String SSL_KEYSTORE = "ssl.keystore";
+ static final String SSL_PASSWORD = "ssl.password";
+ static final String SSL_KEYPASSWORD = "ssl.keypassword";
+ static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
+ static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
+ static final String SSL_PROTOCOL = "ssl.protocol";
+ static final String SSL_ALGORITHM = "ssl.algorithm";
+ static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
+ static final String JETTY_PROPERTY_PREFIX = "org.eclipse.equinox.http.jetty.";
+ // Argeo specific
+ static final String WEBSOCKET_ENABLED = "websocket.enabled";
+
+}
--- /dev/null
+package org.argeo.cms.servlet.internal.jetty;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ForkJoinPool;
+
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
+import org.argeo.cms.security.PkiUtils;
+import org.argeo.cms.websocket.javax.server.CmsWebSocketConfigurator;
+import org.argeo.cms.websocket.javax.server.TestEndpoint;
+import org.argeo.util.LangUtils;
+import org.eclipse.equinox.http.jetty.JettyConfigurator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class JettyConfig {
+ private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
+
+ final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
+ // Argeo specific
+ final static String WEBSOCKET_ENABLED = "websocket.enabled";
+
+ private CmsState cmsState;
+
+ private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
+
+ public void start() {
+ // We need to start asynchronously so that Jetty bundle get started by lazy init
+ // due to the non-configurable behaviour of its activator
+ ForkJoinPool.commonPool().execute(() -> {
+ Dictionary<String, ?> properties = getHttpServerConfig();
+ startServer(properties);
+ });
+
+ ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
+ bc, ServerContainer.class, null) {
+
+ @Override
+ public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
+ ServerContainer serverContainer = super.addingService(reference);
+
+ BundleContext bc = reference.getBundle().getBundleContext();
+ ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
+ .getServiceReference(ServerEndpointConfig.Configurator.class);
+ ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
+ ServerEndpointConfig config = ServerEndpointConfig.Builder
+ .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
+ try {
+ serverContainer.addEndpoint(config);
+ } catch (DeploymentException e) {
+ throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
+ }
+ return serverContainer;
+ }
+
+ };
+ serverSt.open();
+ }
+
+ public void stop() {
+ try {
+ JettyConfigurator.stopServer(CmsConstants.DEFAULT);
+ } catch (Exception e) {
+ log.error("Cannot stop default Jetty server.", e);
+ }
+
+ }
+
+ public void startServer(Dictionary<String, ?> properties) {
+ // Explicitly configures Jetty so that the default server is not started by the
+ // activator of the Equinox Jetty bundle.
+ Map<String, String> config = LangUtils.dictToStringMap(properties);
+ if (!config.isEmpty()) {
+ config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
+
+ // TODO centralise with Jetty extender
+ Object webSocketEnabled = config.get(WEBSOCKET_ENABLED);
+ if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
+ bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
+ config.put(WEBSOCKET_ENABLED, "true");
+ }
+ }
+
+ int tryCount = 30;
+ try {
+ tryGettyJetty: while (tryCount > 0) {
+ try {
+ // FIXME deal with multiple ids
+ JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
+
+ Object httpPort = config.get(InternalHttpConstants.HTTP_PORT);
+ Object httpsPort = config.get(InternalHttpConstants.HTTPS_PORT);
+ log.info(httpPortsMsg(httpPort, httpsPort));
+
+ // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
+ // configuration is not cleaned
+ FrameworkUtil.getBundle(JettyConfigurator.class).start();
+ break tryGettyJetty;
+ } catch (IllegalStateException e) {
+ // e.printStackTrace();
+ // Jetty may not be ready
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e1) {
+ // silent
+ }
+ tryCount--;
+ }
+ }
+ } catch (Exception e) {
+ log.error("Cannot start default Jetty server with config " + properties, e);
+ }
+
+ }
+
+ private String httpPortsMsg(Object httpPort, Object httpsPort) {
+ return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
+ }
+
+ /** Override the provided config with the framework properties */
+ public Dictionary<String, Object> getHttpServerConfig() {
+ String httpPort = getFrameworkProp("org.osgi.service.http.port");
+ String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure");
+ /// TODO make it more generic
+ String httpHost = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTP_HOST);
+ String httpsHost = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTPS_HOST);
+ String webSocketEnabled = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.WEBSOCKET_ENABLED);
+
+ final Hashtable<String, Object> props = new Hashtable<String, Object>();
+ // try {
+ if (httpPort != null || httpsPort != null) {
+ boolean httpEnabled = httpPort != null;
+ props.put(InternalHttpConstants.HTTP_ENABLED, httpEnabled);
+ boolean httpsEnabled = httpsPort != null;
+ props.put(InternalHttpConstants.HTTPS_ENABLED, httpsEnabled);
+
+ if (httpEnabled) {
+ props.put(InternalHttpConstants.HTTP_PORT, httpPort);
+ if (httpHost != null)
+ props.put(InternalHttpConstants.HTTP_HOST, httpHost);
+ }
+
+ if (httpsEnabled) {
+ props.put(InternalHttpConstants.HTTPS_PORT, httpsPort);
+ if (httpsHost != null)
+ props.put(InternalHttpConstants.HTTPS_HOST, httpsHost);
+
+ // server certificate
+ Path keyStorePath = cmsState.getDataPath(PkiUtils.DEFAULT_KEYSTORE_PATH);
+ Path pemKeyPath = cmsState.getDataPath(PkiUtils.DEFAULT_PEM_KEY_PATH);
+ Path pemCertPath = cmsState.getDataPath(PkiUtils.DEFAULT_PEM_CERT_PATH);
+ String keyStorePasswordStr = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_PASSWORD);
+ char[] keyStorePassword;
+ if (keyStorePasswordStr == null)
+ keyStorePassword = "changeit".toCharArray();
+ else
+ keyStorePassword = keyStorePasswordStr.toCharArray();
+
+ // if PEM files both exists, update the PKCS12 file
+ if (Files.exists(pemCertPath) && Files.exists(pemKeyPath)) {
+ // TODO check certificate update time? monitor changes?
+ KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
+ try (Reader key = Files.newBufferedReader(pemKeyPath, StandardCharsets.US_ASCII);
+ Reader cert = Files.newBufferedReader(pemCertPath, StandardCharsets.US_ASCII);) {
+ PkiUtils.loadPem(keyStore, key, keyStorePassword, cert);
+ PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore);
+ if (log.isDebugEnabled())
+ log.debug("PEM certificate stored in " + keyStorePath);
+ } catch (IOException e) {
+ log.error("Cannot read PEM files " + pemKeyPath + " and " + pemCertPath, e);
+ }
+ }
+
+ if (!Files.exists(keyStorePath))
+ PkiUtils.createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
+ props.put(InternalHttpConstants.SSL_KEYSTORETYPE, PkiUtils.PKCS12);
+ props.put(InternalHttpConstants.SSL_KEYSTORE, keyStorePath.toString());
+ props.put(InternalHttpConstants.SSL_PASSWORD, new String(keyStorePassword));
+
+// props.put(InternalHttpConstants.SSL_KEYSTORETYPE, "PKCS11");
+// props.put(InternalHttpConstants.SSL_KEYSTORE, "../../nssdb");
+// props.put(InternalHttpConstants.SSL_PASSWORD, keyStorePassword);
+
+ // client certificate authentication
+ String wantClientAuth = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_WANTCLIENTAUTH);
+ if (wantClientAuth != null)
+ props.put(InternalHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
+ String needClientAuth = getFrameworkProp(
+ InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_NEEDCLIENTAUTH);
+ if (needClientAuth != null)
+ props.put(InternalHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
+ }
+
+ // web socket
+ if (webSocketEnabled != null && webSocketEnabled.equals("true"))
+ props.put(InternalHttpConstants.WEBSOCKET_ENABLED, true);
+
+ props.put(CmsConstants.CN, CmsConstants.DEFAULT);
+ }
+ return props;
+ }
+
+ private String getFrameworkProp(String key) {
+ return cmsState.getDeployProperty(key);
+ }
+
+ public void setCmsState(CmsState cmsState) {
+ this.cmsState = cmsState;
+ }
+
+}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" name="JCR Deployment">
<implementation class="org.argeo.cms.jcr.internal.CmsJcrDeployment"/>
- <reference bind="setCmsDeployment" cardinality="1..1" interface="org.argeo.api.cms.CmsDeployment" policy="static"/>
</scr:component>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Jackrabbit Repository Contexts Factory">
<implementation class="org.argeo.cms.jcr.internal.RepositoryContextsFactory"/>
<property name="service.pid" type="String" value="org.argeo.api.repos"/>
- <service>
- <provide interface="org.osgi.service.cm.ManagedServiceFactory"/>
- </service>
- <reference cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+ <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
</scr:component>
import org.osgi.framework.FrameworkUtil;
/** JCR specific init utilities. */
+@Deprecated
public class JcrInitUtils {
private final static CmsLog log = CmsLog.getLog(JcrInitUtils.class);
private final static BundleContext bundleContext = FrameworkUtil.getBundle(JcrInitUtils.class).getBundleContext();
- public static void addToDeployment(CmsDeployment nodeDeployment) {
- // node repository
-// Dictionary<String, Object> provided = null;
- Dictionary<String, Object> provided = nodeDeployment.getProps(CmsConstants.NODE_REPOS_FACTORY_PID,
- CmsConstants.NODE);
- Dictionary<String, Object> nodeConfig = JcrInitUtils.getNodeRepositoryConfig(provided);
- // node repository is mandatory
- nodeDeployment.addFactoryDeployConfig(CmsConstants.NODE_REPOS_FACTORY_PID, nodeConfig);
-
- // additional repositories
-// dataModels: for (DataModels.DataModel dataModel : dataModels.getNonAbstractDataModels()) {
-// if (NodeConstants.NODE_REPOSITORY.equals(dataModel.getName()))
-// continue dataModels;
-// Dictionary<String, Object> config = JcrInitUtils.getRepositoryConfig(dataModel.getName(),
-// getProps(NodeConstants.NODE_REPOS_FACTORY_PID, dataModel.getName()));
-// if (config.size() != 0)
-// putFactoryDeployConfig(NodeConstants.NODE_REPOS_FACTORY_PID, config);
-// }
-
- }
+// public static void addToDeployment(CmsDeployment nodeDeployment) {
+// // node repository
+//// Dictionary<String, Object> provided = null;
+// Dictionary<String, Object> provided = nodeDeployment.getProps(CmsConstants.NODE_REPOS_FACTORY_PID,
+// CmsConstants.NODE);
+// Dictionary<String, Object> nodeConfig = JcrInitUtils.getNodeRepositoryConfig(provided);
+// // node repository is mandatory
+// nodeDeployment.addFactoryDeployConfig(CmsConstants.NODE_REPOS_FACTORY_PID, nodeConfig);
+//
+// // additional repositories
+//// dataModels: for (DataModels.DataModel dataModel : dataModels.getNonAbstractDataModels()) {
+//// if (NodeConstants.NODE_REPOSITORY.equals(dataModel.getName()))
+//// continue dataModels;
+//// Dictionary<String, Object> config = JcrInitUtils.getRepositoryConfig(dataModel.getName(),
+//// getProps(NodeConstants.NODE_REPOS_FACTORY_PID, dataModel.getName()));
+//// if (config.size() != 0)
+//// putFactoryDeployConfig(NodeConstants.NODE_REPOS_FACTORY_PID, config);
+//// }
+//
+// }
/** Override the provided config with the framework properties */
public static Dictionary<String, Object> getNodeRepositoryConfig(Dictionary<String, Object> provided) {
return props;
}
- public static Dictionary<String, Object> getRepositoryConfig(String dataModelName,
- Dictionary<String, Object> provided) {
- if (dataModelName.equals(CmsConstants.NODE_REPOSITORY) || dataModelName.equals(CmsConstants.EGO_REPOSITORY))
- throw new IllegalArgumentException("Data model '" + dataModelName + "' is reserved.");
- Dictionary<String, Object> props = provided != null ? provided : new Hashtable<String, Object>();
- for (RepoConf repoConf : RepoConf.values()) {
- Object value = getFrameworkProp(
- CmsConstants.NODE_REPOS_PROP_PREFIX + dataModelName + '.' + repoConf.name());
- if (value != null) {
- props.put(repoConf.name(), value);
- if (log.isDebugEnabled())
- log.debug("Set " + dataModelName + " repo configuration " + repoConf.name() + " to " + value);
- }
- }
- if (props.size() != 0)
- props.put(CmsConstants.CN, dataModelName);
- return props;
- }
+// public static Dictionary<String, Object> getRepositoryConfig(String dataModelName,
+// Dictionary<String, Object> provided) {
+// if (dataModelName.equals(CmsConstants.NODE_REPOSITORY) || dataModelName.equals(CmsConstants.EGO_REPOSITORY))
+// throw new IllegalArgumentException("Data model '" + dataModelName + "' is reserved.");
+// Dictionary<String, Object> props = provided != null ? provided : new Hashtable<String, Object>();
+// for (RepoConf repoConf : RepoConf.values()) {
+// Object value = getFrameworkProp(
+// CmsConstants.NODE_REPOS_PROP_PREFIX + dataModelName + '.' + repoConf.name());
+// if (value != null) {
+// props.put(repoConf.name(), value);
+// if (log.isDebugEnabled())
+// log.debug("Set " + dataModelName + " repo configuration " + repoConf.name() + " to " + value);
+// }
+// }
+// if (props.size() != 0)
+// props.put(CmsConstants.CN, dataModelName);
+// return props;
+// }
private static void registerRemoteInit(String uri) {
try {
// Readiness
private boolean nodeAvailable = false;
- CmsDeployment cmsDeployment;
+// CmsDeployment cmsDeployment;
public void start() {
dataModels = new DataModels(bc);
// nodeDeployment = CmsJcrActivator.getService(NodeDeployment.class);
- JcrInitUtils.addToDeployment(cmsDeployment);
+ //JcrInitUtils.addToDeployment(cmsDeployment);
// contentRepository.registerTypes(NamespaceRegistry.PREFIX_JCR, NamespaceRegistry.NAMESPACE_JCR, null);
// contentRepository.registerTypes(NamespaceRegistry.PREFIX_MIX, NamespaceRegistry.NAMESPACE_MIX, null);
}
- public void setCmsDeployment(CmsDeployment cmsDeployment) {
- this.cmsDeployment = cmsDeployment;
- }
+// public void setCmsDeployment(CmsDeployment cmsDeployment) {
+// this.cmsDeployment = cmsDeployment;
+// }
/**
* Checks whether the deployment is available according to expectations, and
}
boolean isStandalone(String dataModelName) {
- return cmsDeployment.getProps(CmsConstants.NODE_REPOS_FACTORY_PID, dataModelName) != null;
+ return true;
+ //return cmsDeployment.getProps(CmsConstants.NODE_REPOS_FACTORY_PID, dataModelName) != null;
}
private void publishLocalRepo(String dataModelName, Repository repository) {
import java.net.URISyntaxException;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.Hashtable;
import java.util.Map;
import javax.jcr.Repository;
import org.apache.jackrabbit.core.RepositoryContext;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
import org.argeo.cms.internal.jcr.RepoConf;
import org.argeo.cms.internal.jcr.RepositoryBuilder;
import org.argeo.cms.jcr.internal.osgi.CmsJcrActivator;
import org.argeo.util.LangUtils;
-import org.osgi.framework.Constants;
-import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
/** A {@link ManagedServiceFactory} creating or referencing JCR repositories. */
-public class RepositoryContextsFactory implements ManagedServiceFactory {
+public class RepositoryContextsFactory {
private final static CmsLog log = CmsLog.getLog(RepositoryContextsFactory.class);
// private final BundleContext bc = FrameworkUtil.getBundle(RepositoryServiceFactory.class).getBundleContext();
- private Map<String, RepositoryContext> repositories = new HashMap<String, RepositoryContext>();
- private Map<String, Object> pidToCn = new HashMap<String, Object>();
+// private Map<String, RepositoryContext> repositories = new HashMap<String, RepositoryContext>();
+// private Map<String, Object> pidToCn = new HashMap<String, Object>();
- public void init() {
+ private RepositoryContext repositoryContext;
+
+ private CmsState cmsState;
+ public void init() {
+ Dictionary<String, Object> config = getNodeRepositoryConfig();
+ deployRepository(config);
}
public void destroy() {
- for (String pid : repositories.keySet()) {
- try {
- RepositoryContext repositoryContext = repositories.get(pid);
- // Must start in another thread otherwise shutdown is interrupted
- // TODO use an executor?
- new Thread(() -> {
- repositoryContext.getRepository().shutdown();
- if (log.isDebugEnabled())
- log.debug("Shut down repository " + pid
- + (pidToCn.containsKey(pid) ? " (" + pidToCn.get(pid) + ")" : ""));
- }, "Shutdown JCR repository " + pid).start();
- } catch (Exception e) {
- log.error("Error when shutting down Jackrabbit repository " + pid, e);
- }
+ if (this.repositoryContext != null) {
+ this.repositoryContext.getRepository().shutdown();
}
+// for (String pid : repositories.keySet()) {
+// try {
+// RepositoryContext repositoryContext = repositories.get(pid);
+// // Must start in another thread otherwise shutdown is interrupted
+// // TODO use an executor?
+// new Thread(() -> {
+// repositoryContext.getRepository().shutdown();
+// if (log.isDebugEnabled())
+// log.debug("Shut down repository " + pid
+// + (pidToCn.containsKey(pid) ? " (" + pidToCn.get(pid) + ")" : ""));
+// }, "Shutdown JCR repository " + pid).start();
+// } catch (Exception e) {
+// log.error("Error when shutting down Jackrabbit repository " + pid, e);
+// }
+// }
}
- @Override
- public String getName() {
- return "Jackrabbit repository service factory";
+// @Override
+// public String getName() {
+// return "Jackrabbit repository service factory";
+// }
+
+ /** Override the provided config with the framework properties */
+ private Dictionary<String, Object> getNodeRepositoryConfig() {
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ for (RepoConf repoConf : RepoConf.values()) {
+ Object value = getFrameworkProp(CmsConstants.NODE_REPO_PROP_PREFIX + repoConf.name());
+ if (value != null) {
+ props.put(repoConf.name(), value);
+ if (log.isDebugEnabled())
+ log.debug("Set node repo configuration " + repoConf.name() + " to " + value);
+ }
+ }
+ props.put(CmsConstants.CN, CmsConstants.NODE_REPOSITORY);
+ return props;
}
- @Override
- public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
- if (repositories.containsKey(pid))
- throw new IllegalArgumentException("Already a repository registered for " + pid);
+// @Override
+// public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
+ protected void deployRepository(Dictionary<String, Object> properties) {
+// if (repositories.containsKey(pid))
+// throw new IllegalArgumentException("Already a repository registered for " + pid);
if (properties == null)
return;
Object cn = properties.get(CmsConstants.CN);
- if (cn != null)
- for (String otherPid : pidToCn.keySet()) {
- Object o = pidToCn.get(otherPid);
- if (cn.equals(o)) {
- RepositoryContext repositoryContext = repositories.remove(otherPid);
- repositories.put(pid, repositoryContext);
- if (log.isDebugEnabled())
- log.debug("Ignoring update of Jackrabbit repository " + cn);
- // FIXME perform a proper update (also of the OSGi service)
- return;
- }
- }
+// if (cn != null)
+// for (String otherPid : pidToCn.keySet()) {
+// Object o = pidToCn.get(otherPid);
+// if (cn.equals(o)) {
+// RepositoryContext repositoryContext = repositories.remove(otherPid);
+// repositories.put(pid, repositoryContext);
+// if (log.isDebugEnabled())
+// log.debug("Ignoring update of Jackrabbit repository " + cn);
+// // FIXME perform a proper update (also of the OSGi service)
+// return;
+// }
+// }
try {
Object labeledUri = properties.get(RepoConf.labeledUri.name());
if (labeledUri == null) {
RepositoryBuilder repositoryBuilder = new RepositoryBuilder();
RepositoryContext repositoryContext = repositoryBuilder.createRepositoryContext(properties);
- repositories.put(pid, repositoryContext);
- Dictionary<String, Object> props = LangUtils.dict(Constants.SERVICE_PID, pid);
+// repositories.put(pid, repositoryContext);
+// Dictionary<String, Object> props = LangUtils.dict(Constants.SERVICE_PID, pid);
+ Dictionary<String, Object> props = new Hashtable<>();
// props.put(ArgeoJcrConstants.JCR_REPOSITORY_URI,
// properties.get(RepoConf.labeledUri.name()));
if (cn != null) {
props.put(CmsConstants.CN, cn);
// props.put(NodeConstants.JCR_REPOSITORY_ALIAS, cn);
- pidToCn.put(pid, cn);
+// pidToCn.put(pid, cn);
}
CmsJcrActivator.registerService(RepositoryContext.class, repositoryContext, props);
+ this.repositoryContext = repositoryContext;
} else {
Object defaultWorkspace = properties.get(RepoConf.defaultWorkspace.name());
if (defaultWorkspace == null)
Repository repository = repositoryFactory.getRepository(parameters);
// Repository repository = NodeUtils.getRepositoryByUri(repositoryFactory,
// uri.toString());
- Dictionary<String, Object> props = LangUtils.dict(Constants.SERVICE_PID, pid);
+// Dictionary<String, Object> props = LangUtils.dict(Constants.SERVICE_PID, pid);
+ Dictionary<String, Object> props = new Hashtable<>();
props.put(RepoConf.labeledUri.name(),
new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), null, null)
.toString());
if (cn != null) {
props.put(CmsConstants.CN, cn);
- // props.put(NodeConstants.JCR_REPOSITORY_ALIAS, cn);
- pidToCn.put(pid, cn);
+// pidToCn.put(pid, cn);
}
CmsJcrActivator.registerService(Repository.class, repository, props);
}
}
} catch (RepositoryException | URISyntaxException | IOException e) {
- throw new IllegalStateException("Cannot create Jackrabbit repository " + pid, e);
+ throw new IllegalStateException("Cannot create Jackrabbit repository " + properties, e);
}
}
- @Override
- public void deleted(String pid) {
- RepositoryContext repositoryContext = repositories.remove(pid);
- repositoryContext.getRepository().shutdown();
- if (log.isDebugEnabled())
- log.debug("Deleted repository " + pid);
+// @Override
+// public void deleted(String pid) {
+// RepositoryContext repositoryContext = repositories.remove(pid);
+// repositoryContext.getRepository().shutdown();
+// if (log.isDebugEnabled())
+// log.debug("Deleted repository " + pid);
+// }
+
+ private String getFrameworkProp(String key) {
+ return cmsState.getDeployProperty(key);
+ }
+
+ public void setCmsState(CmsState cmsState) {
+ this.cmsState = cmsState;
}
}
/** A configured node deployment. */
public interface CmsDeployment {
- void addFactoryDeployConfig(String factoryPid, Dictionary<String, Object> props);
-
- Dictionary<String, Object> getProps(String factoryPid, String cn);
+// void addFactoryDeployConfig(String factoryPid, Dictionary<String, Object> props);
+//
+// Dictionary<String, Object> getProps(String factoryPid, String cn);
}
package org.argeo.api.cms;
+import java.nio.file.Path;
import java.util.UUID;
/** A running node process. */
Long getAvailableSince();
UUID getUuid();
+
+ String getDeployProperty(String key);
+
+ Path getDataPath(String relativePath);
}
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="false" name="CMS Deployment">
- <reference bind="setDeployConfig" cardinality="1..1" interface="org.argeo.cms.internal.osgi.DeployConfig" name="DeployConfig" policy="static"/>
<implementation class="org.argeo.cms.internal.runtime.CmsDeploymentImpl"/>
<reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
<service>
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="start" deactivate="stop" immediate="false" name="Node User Admin">
- <implementation class="org.argeo.cms.internal.osgi.NodeUserAdmin"/>
+ <implementation class="org.argeo.cms.internal.runtime.CmsUserAdmin"/>
<property name="service.pid" type="String" value="org.argeo.api.userAdmin"/>
- <service>
- <provide interface="org.osgi.service.cm.ManagedServiceFactory"/>
- </service>
<reference bind="setTransactionManager" cardinality="1..1" interface="org.argeo.util.transaction.WorkControl" name="WorkControl" policy="static"/>
<reference bind="setUserTransaction" cardinality="1..1" interface="org.argeo.util.transaction.WorkTransaction" name="WorkTransaction" policy="static"/>
- <reference cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+ <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+ <service>
+ <provide interface="org.osgi.service.useradmin.UserAdmin"/>
+ </service>
</scr:component>
OSGI-INF/simpleTransactionManager.xml,\
OSGI-INF/nodeUserAdmin.xml,\
OSGI-INF/cmsUserManager.xml,\
-OSGI-INF/deployConfig.xml,\
OSGI-INF/uuidFactory.xml,\
OSGI-INF/acrContentRepository.xml,\
OSGI-INF/cmsDeployment.xml,\
if (log.isDebugEnabled())
log.debug("Client certificate " + certDn + " verified by servlet container");
} // Reverse proxy verified the client certificate
- String clientDnHttpHeader = KernelUtils.getFrameworkProp(CmsConstants.HTTP_PROXY_SSL_DN);
+ String clientDnHttpHeader = CmsContextImpl.getCmsContext().getCmsState()
+ .getDeployProperty(CmsConstants.HTTP_PROXY_SSL_DN);
if (clientDnHttpHeader != null) {
String certDn = req.getHeader(clientDnHttpHeader);
// TODO retrieve more cf. https://httpd.apache.org/docs/current/mod/mod_ssl.html
+++ /dev/null
-package org.argeo.cms.internal.http;
-
-/** Compatible with Jetty. */
-public interface InternalHttpConstants {
- static final String HTTP_ENABLED = "http.enabled";
- static final String HTTP_PORT = "http.port";
- static final String HTTP_HOST = "http.host";
- static final String HTTPS_ENABLED = "https.enabled";
- static final String HTTPS_HOST = "https.host";
- static final String HTTPS_PORT = "https.port";
- static final String SSL_KEYSTORE = "ssl.keystore";
- static final String SSL_PASSWORD = "ssl.password";
- static final String SSL_KEYPASSWORD = "ssl.keypassword";
- static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
- static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
- static final String SSL_PROTOCOL = "ssl.protocol";
- static final String SSL_ALGORITHM = "ssl.algorithm";
- static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
- static final String JETTY_PROPERTY_PREFIX = "org.eclipse.equinox.http.jetty.";
- // Argeo specific
- static final String WEBSOCKET_ENABLED = "websocket.enabled";
-
-}
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceReference;
import org.osgi.service.condpermadmin.BundleLocationCondition;
import org.osgi.service.condpermadmin.ConditionInfo;
import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
import org.osgi.service.condpermadmin.ConditionalPermissionInfo;
import org.osgi.service.condpermadmin.ConditionalPermissionUpdate;
-import org.osgi.service.http.HttpService;
import org.osgi.service.log.LogReaderService;
import org.osgi.service.permissionadmin.PermissionInfo;
-import org.osgi.util.tracker.ServiceTracker;
/**
* Activates the kernel. Gives access to kernel information for the rest of the
// userAdminSt = new ServiceTracker<>(bundleContext, UserAdmin.class, null);
// userAdminSt.open();
- ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
-
- @Override
- public HttpService addingService(ServiceReference<HttpService> sr) {
- Object httpPort = sr.getProperty("http.port");
- Object httpsPort = sr.getProperty("https.port");
- log.info(httpPortsMsg(httpPort, httpsPort));
- close();
- return super.addingService(sr);
- }
- };
- httpSt.open();
+// ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
+//
+// @Override
+// public HttpService addingService(ServiceReference<HttpService> sr) {
+// Object httpPort = sr.getProperty("http.port");
+// Object httpsPort = sr.getProperty("https.port");
+// log.info(httpPortsMsg(httpPort, httpsPort));
+// close();
+// return super.addingService(sr);
+// }
+// };
+// httpSt.open();
}
private String httpPortsMsg(Object httpPort, Object httpsPort) {
private void setFromFrameworkProperties(boolean isFirstInit) {
// user admin
- List<Dictionary<String, Object>> userDirectoryConfigs = InitUtils.getUserDirectoryConfigs();
- if (userDirectoryConfigs.size() != 0) {
- List<String> activeCns = new ArrayList<>();
- for (int i = 0; i < userDirectoryConfigs.size(); i++) {
- Dictionary<String, Object> userDirectoryConfig = userDirectoryConfigs.get(i);
- String baseDn = (String) userDirectoryConfig.get(DirectoryConf.baseDn.name());
- String cn;
- if (CmsConstants.ROLES_BASEDN.equals(baseDn))
- cn = ROLES;
- else
- cn = DirectoryConf.baseDnHash(userDirectoryConfig);
- activeCns.add(cn);
- userDirectoryConfig.put(CmsConstants.CN, cn);
- putFactoryDeployConfig(CmsConstants.NODE_USER_ADMIN_PID, userDirectoryConfig);
- }
- // disable others
- LdapName userAdminFactoryName = serviceFactoryDn(CmsConstants.NODE_USER_ADMIN_PID);
- for (LdapName name : deployConfigs.keySet()) {
- if (name.startsWith(userAdminFactoryName) && !name.equals(userAdminFactoryName)) {
-// try {
- Attributes attrs = deployConfigs.get(name);
- String cn = name.getRdn(name.size() - 1).getValue().toString();
- if (!activeCns.contains(cn)) {
- attrs.put(DirectoryConf.disabled.name(), "true");
- }
-// } catch (Exception e) {
-// throw new CmsException("Cannot disable user directory " + name, e);
+// List<Dictionary<String, Object>> userDirectoryConfigs = InitUtils.getUserDirectoryConfigs();
+// if (userDirectoryConfigs.size() != 0) {
+// List<String> activeCns = new ArrayList<>();
+// for (int i = 0; i < userDirectoryConfigs.size(); i++) {
+// Dictionary<String, Object> userDirectoryConfig = userDirectoryConfigs.get(i);
+// String baseDn = (String) userDirectoryConfig.get(DirectoryConf.baseDn.name());
+// String cn;
+// if (CmsConstants.ROLES_BASEDN.equals(baseDn))
+// cn = ROLES;
+// else
+// cn = DirectoryConf.baseDnHash(userDirectoryConfig);
+// activeCns.add(cn);
+// userDirectoryConfig.put(CmsConstants.CN, cn);
+// putFactoryDeployConfig(CmsConstants.NODE_USER_ADMIN_PID, userDirectoryConfig);
+// }
+// // disable others
+// LdapName userAdminFactoryName = serviceFactoryDn(CmsConstants.NODE_USER_ADMIN_PID);
+// for (LdapName name : deployConfigs.keySet()) {
+// if (name.startsWith(userAdminFactoryName) && !name.equals(userAdminFactoryName)) {
+//// try {
+// Attributes attrs = deployConfigs.get(name);
+// String cn = name.getRdn(name.size() - 1).getValue().toString();
+// if (!activeCns.contains(cn)) {
+// attrs.put(DirectoryConf.disabled.name(), "true");
// }
- }
- }
- }
+//// } catch (Exception e) {
+//// throw new CmsException("Cannot disable user directory " + name, e);
+//// }
+// }
+// }
+// }
// http server
- Dictionary<String, Object> webServerConfig = InitUtils
- .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, CmsConstants.DEFAULT));
- if (!webServerConfig.isEmpty()) {
- // TODO check for other customizers
-// webServerConfig.put("customizer.class", "org.argeo.equinox.jetty.CmsJettyCustomizer");
- putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig);
- }
-// LdapName defaultHttpServiceDn = serviceDn(KernelConstants.JETTY_FACTORY_PID, CmsConstants.DEFAULT);
-// if (deployConfigs.containsKey(defaultHttpServiceDn)) {
-// // remove old default configs since we have now to start Jetty servlet bridge
-// // indirectly
-// deployConfigs.remove(defaultHttpServiceDn);
+// Dictionary<String, Object> webServerConfig = InitUtils
+// .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, CmsConstants.DEFAULT));
+// if (!webServerConfig.isEmpty()) {
+// // TODO check for other customizers
+// putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig);
// }
// SAVE
save();
//
-// Dictionary<String, Object> webServerConfig = InitUtils
-// .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, CmsConstants.DEFAULT));
}
public void start() {
private HttpService httpService;
private CmsState cmsState;
- private DeployConfig deployConfig;
+// private DeployConfig deployConfig;
public void start() {
- httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
- if (deployConfig.hasDomain()) {
- loadIpaJaasConfiguration();
- }
+// httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null;
+// if (deployConfig.hasDomain()) {
+// loadIpaJaasConfiguration();
+// }
}
- public void addFactoryDeployConfig(String factoryPid, Dictionary<String, Object> props) {
- deployConfig.putFactoryDeployConfig(factoryPid, props);
- deployConfig.save();
- try {
- deployConfig.loadConfigs();
- } catch (IOException e) {
- throw new IllegalStateException(e);
- }
- }
-
- public Dictionary<String, Object> getProps(String factoryPid, String cn) {
- return deployConfig.getProps(factoryPid, cn);
- }
+// public void addFactoryDeployConfig(String factoryPid, Dictionary<String, Object> props) {
+// deployConfig.putFactoryDeployConfig(factoryPid, props);
+// deployConfig.save();
+// try {
+// deployConfig.loadConfigs();
+// } catch (IOException e) {
+// throw new IllegalStateException(e);
+// }
+// }
+//
+// public Dictionary<String, Object> getProps(String factoryPid, String cn) {
+// return deployConfig.getProps(factoryPid, cn);
+// }
public boolean isHttpAvailableOrNotExpected() {
return (httpExpected ? httpService != null : true);
}
public void stop() {
- if (deployConfig != null) {
- deployConfig.save();
- }
+// if (deployConfig != null) {
+// deployConfig.save();
+// }
}
- public void setDeployConfig(DeployConfig deployConfig) {
- this.deployConfig = deployConfig;
- }
+// public void setDeployConfig(DeployConfig deployConfig) {
+// this.deployConfig = deployConfig;
+// }
public void setCmsState(CmsState cmsState) {
this.cmsState = cmsState;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
+import java.nio.file.Path;
import java.util.UUID;
import javax.security.auth.login.Configuration;
log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##");
}
+ @Override
+ public String getDeployProperty(String key) {
+ return KernelUtils.getFrameworkProp(key);
+ }
+
+ @Override
+ public Path getDataPath(String relativePath) {
+ return KernelUtils.getOsgiInstancePath(relativePath);
+ }
+
@Override
public Long getAvailableSince() {
return availableSince;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Iterator;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.argeo.api.cms.CmsAuth;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
import org.argeo.cms.internal.http.client.HttpCredentialProvider;
import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
-import org.argeo.osgi.useradmin.DirectoryUserAdmin;
import org.argeo.osgi.useradmin.AggregatingUserAdmin;
+import org.argeo.osgi.useradmin.DirectoryUserAdmin;
import org.argeo.osgi.useradmin.UserDirectory;
import org.argeo.util.directory.DirectoryConf;
import org.argeo.util.naming.dns.DnsBrowser;
private WorkControl transactionManager;
private WorkTransaction userTransaction;
+ private CmsState cmsState;
+
public CmsUserAdmin() {
super(CmsConstants.ROLES_BASEDN, CmsConstants.TOKENS_BASEDN);
}
public void start() {
+ super.start();
+ List<Dictionary<String, Object>> configs = InitUtils.getUserDirectoryConfigs();
+ for (Dictionary<String, Object> config : configs) {
+ UserDirectory userDirectory = enableUserDirectory(config);
+ if (userDirectory.getRealm().isPresent())
+ loadIpaJaasConfiguration();
+ }
}
public void stop() {
+// for (UserDirectory userDirectory : getUserDirectories()) {
+// removeUserDirectory(userDirectory);
+// }
+ super.stop();
}
public UserDirectory enableUserDirectory(Dictionary<String, ?> properties) {
}
}
+ private void loadIpaJaasConfiguration() {
+ if (System.getProperty(KernelConstants.JAAS_CONFIG_PROP) == null) {
+ String jaasConfig = KernelConstants.JAAS_CONFIG_IPA;
+ URL url = getClass().getClassLoader().getResource(jaasConfig);
+ KernelUtils.setJaasConfiguration(url);
+ log.debug("Set IPA JAAS configuration.");
+ }
+ }
+
private String getKerberosServicePrincipal(String realm) {
String hostname;
try (DnsBrowser dnsBrowser = new DnsBrowser()) {
this.userTransaction = userTransaction;
}
- /*
- * STATIC
- */
+ public void setCmsState(CmsState cmsState) {
+ this.cmsState = cmsState;
+ }
}
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
-import java.io.Reader;
-import java.net.InetAddress;
import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.KeyStore;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Dictionary;
-import java.util.Hashtable;
import java.util.List;
-import javax.security.auth.x500.X500Principal;
-
import org.apache.commons.io.FileUtils;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.internal.http.InternalHttpConstants;
import org.argeo.util.directory.DirectoryConf;
/**
private final static CmsLog log = CmsLog.getLog(InitUtils.class);
/** Override the provided config with the framework properties */
- public static Dictionary<String, Object> getHttpServerConfig(Dictionary<String, Object> provided) {
- String httpPort = getFrameworkProp("org.osgi.service.http.port");
- String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure");
- /// TODO make it more generic
- String httpHost = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTP_HOST);
- String httpsHost = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTPS_HOST);
- String webSocketEnabled = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.WEBSOCKET_ENABLED);
-
- final Hashtable<String, Object> props = new Hashtable<String, Object>();
- // try {
- if (httpPort != null || httpsPort != null) {
- boolean httpEnabled = httpPort != null;
- props.put(InternalHttpConstants.HTTP_ENABLED, httpEnabled);
- boolean httpsEnabled = httpsPort != null;
- props.put(InternalHttpConstants.HTTPS_ENABLED, httpsEnabled);
-
- if (httpEnabled) {
- props.put(InternalHttpConstants.HTTP_PORT, httpPort);
- if (httpHost != null)
- props.put(InternalHttpConstants.HTTP_HOST, httpHost);
- }
-
- if (httpsEnabled) {
- props.put(InternalHttpConstants.HTTPS_PORT, httpsPort);
- if (httpsHost != null)
- props.put(InternalHttpConstants.HTTPS_HOST, httpsHost);
-
- // server certificate
- Path keyStorePath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_KEYSTORE_PATH);
- Path pemKeyPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_KEY_PATH);
- Path pemCertPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_CERT_PATH);
- String keyStorePasswordStr = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_PASSWORD);
- char[] keyStorePassword;
- if (keyStorePasswordStr == null)
- keyStorePassword = "changeit".toCharArray();
- else
- keyStorePassword = keyStorePasswordStr.toCharArray();
-
- // if PEM files both exists, update the PKCS12 file
- if (Files.exists(pemCertPath) && Files.exists(pemKeyPath)) {
- // TODO check certificate update time? monitor changes?
- KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
- try (Reader key = Files.newBufferedReader(pemKeyPath, StandardCharsets.US_ASCII);
- Reader cert = Files.newBufferedReader(pemCertPath, StandardCharsets.US_ASCII);) {
- PkiUtils.loadPem(keyStore, key, keyStorePassword, cert);
- PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore);
- if (log.isDebugEnabled())
- log.debug("PEM certificate stored in " + keyStorePath);
- } catch (IOException e) {
- log.error("Cannot read PEM files " + pemKeyPath + " and " + pemCertPath, e);
- }
- }
-
- if (!Files.exists(keyStorePath))
- createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
- props.put(InternalHttpConstants.SSL_KEYSTORETYPE, PkiUtils.PKCS12);
- props.put(InternalHttpConstants.SSL_KEYSTORE, keyStorePath.toString());
- props.put(InternalHttpConstants.SSL_PASSWORD, new String(keyStorePassword));
-
-// props.put(InternalHttpConstants.SSL_KEYSTORETYPE, "PKCS11");
-// props.put(InternalHttpConstants.SSL_KEYSTORE, "../../nssdb");
-// props.put(InternalHttpConstants.SSL_PASSWORD, keyStorePassword);
-
- // client certificate authentication
- String wantClientAuth = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_WANTCLIENTAUTH);
- if (wantClientAuth != null)
- props.put(InternalHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
- String needClientAuth = getFrameworkProp(
- InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_NEEDCLIENTAUTH);
- if (needClientAuth != null)
- props.put(InternalHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
- }
-
- // web socket
- if (webSocketEnabled != null && webSocketEnabled.equals("true"))
- props.put(InternalHttpConstants.WEBSOCKET_ENABLED, true);
-
- props.put(CmsConstants.CN, CmsConstants.DEFAULT);
- }
- return props;
- }
+// public static Dictionary<String, Object> getHttpServerConfig(Dictionary<String, Object> provided) {
+// String httpPort = getFrameworkProp("org.osgi.service.http.port");
+// String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure");
+// /// TODO make it more generic
+// String httpHost = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTP_HOST);
+// String httpsHost = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTPS_HOST);
+// String webSocketEnabled = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.WEBSOCKET_ENABLED);
+//
+// final Hashtable<String, Object> props = new Hashtable<String, Object>();
+// // try {
+// if (httpPort != null || httpsPort != null) {
+// boolean httpEnabled = httpPort != null;
+// props.put(InternalHttpConstants.HTTP_ENABLED, httpEnabled);
+// boolean httpsEnabled = httpsPort != null;
+// props.put(InternalHttpConstants.HTTPS_ENABLED, httpsEnabled);
+//
+// if (httpEnabled) {
+// props.put(InternalHttpConstants.HTTP_PORT, httpPort);
+// if (httpHost != null)
+// props.put(InternalHttpConstants.HTTP_HOST, httpHost);
+// }
+//
+// if (httpsEnabled) {
+// props.put(InternalHttpConstants.HTTPS_PORT, httpsPort);
+// if (httpsHost != null)
+// props.put(InternalHttpConstants.HTTPS_HOST, httpsHost);
+//
+// // server certificate
+// Path keyStorePath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_KEYSTORE_PATH);
+// Path pemKeyPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_KEY_PATH);
+// Path pemCertPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_CERT_PATH);
+// String keyStorePasswordStr = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_PASSWORD);
+// char[] keyStorePassword;
+// if (keyStorePasswordStr == null)
+// keyStorePassword = "changeit".toCharArray();
+// else
+// keyStorePassword = keyStorePasswordStr.toCharArray();
+//
+// // if PEM files both exists, update the PKCS12 file
+// if (Files.exists(pemCertPath) && Files.exists(pemKeyPath)) {
+// // TODO check certificate update time? monitor changes?
+// KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
+// try (Reader key = Files.newBufferedReader(pemKeyPath, StandardCharsets.US_ASCII);
+// Reader cert = Files.newBufferedReader(pemCertPath, StandardCharsets.US_ASCII);) {
+// PkiUtils.loadPem(keyStore, key, keyStorePassword, cert);
+// PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore);
+// if (log.isDebugEnabled())
+// log.debug("PEM certificate stored in " + keyStorePath);
+// } catch (IOException e) {
+// log.error("Cannot read PEM files " + pemKeyPath + " and " + pemCertPath, e);
+// }
+// }
+//
+// if (!Files.exists(keyStorePath))
+// createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12);
+// props.put(InternalHttpConstants.SSL_KEYSTORETYPE, PkiUtils.PKCS12);
+// props.put(InternalHttpConstants.SSL_KEYSTORE, keyStorePath.toString());
+// props.put(InternalHttpConstants.SSL_PASSWORD, new String(keyStorePassword));
+//
+//// props.put(InternalHttpConstants.SSL_KEYSTORETYPE, "PKCS11");
+//// props.put(InternalHttpConstants.SSL_KEYSTORE, "../../nssdb");
+//// props.put(InternalHttpConstants.SSL_PASSWORD, keyStorePassword);
+//
+// // client certificate authentication
+// String wantClientAuth = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_WANTCLIENTAUTH);
+// if (wantClientAuth != null)
+// props.put(InternalHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
+// String needClientAuth = getFrameworkProp(
+// InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_NEEDCLIENTAUTH);
+// if (needClientAuth != null)
+// props.put(InternalHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
+// }
+//
+// // web socket
+// if (webSocketEnabled != null && webSocketEnabled.equals("true"))
+// props.put(InternalHttpConstants.WEBSOCKET_ENABLED, true);
+//
+// props.put(CmsConstants.CN, CmsConstants.DEFAULT);
+// }
+// return props;
+// }
public static List<Dictionary<String, Object>> getUserDirectoryConfigs() {
List<Dictionary<String, Object>> res = new ArrayList<>();
}
}
- private static void createSelfSignedKeyStore(Path keyStorePath, char[] keyStorePassword, String keyStoreType) {
- // for (Provider provider : Security.getProviders())
- // System.out.println(provider.getName());
-// File keyStoreFile = keyStorePath.toFile();
- char[] keyPwd = Arrays.copyOf(keyStorePassword, keyStorePassword.length);
- if (!Files.exists(keyStorePath)) {
- try {
- Files.createDirectories(keyStorePath.getParent());
- KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, keyStoreType);
- PkiUtils.generateSelfSignedCertificate(keyStore,
- new X500Principal("CN=" + InetAddress.getLocalHost().getHostName() + ",OU=UNSECURE,O=UNSECURE"),
- 1024, keyPwd);
- PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore);
- if (log.isDebugEnabled())
- log.debug("Created self-signed unsecure keystore " + keyStorePath);
- } catch (Exception e) {
- try {
- if (Files.size(keyStorePath) == 0)
- Files.delete(keyStorePath);
- } catch (IOException e1) {
- // silent
- }
- log.error("Cannot create keystore " + keyStorePath, e);
- }
- } else {
- throw new IllegalStateException("Keystore " + keyStorePath + " already exists");
- }
- }
-
}
// Files
String DEPLOY_CONFIG_PATH = DIR_NODE + '/' + CmsConstants.DEPLOY_BASEDN + ".ldif";
- String DEFAULT_KEYSTORE_PATH = DIR_NODE + '/' + CmsConstants.NODE + ".p12";
- String DEFAULT_PEM_KEY_PATH = DIR_NODE + '/' + CmsConstants.NODE + ".key";
- String DEFAULT_PEM_CERT_PATH = DIR_NODE + '/' + CmsConstants.NODE + ".crt";
String NODE_KEY_TAB_PATH = DIR_NODE + "/krb5.keytab";
// Security
return value;
}
- public static String getFrameworkProp(String key) {
+ static String getFrameworkProp(String key) {
return getFrameworkProp(key, null);
}
+++ /dev/null
-package org.argeo.cms.internal.runtime;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.math.BigInteger;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.PrivateKey;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-
-import javax.security.auth.x500.X500Principal;
-
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.InputDecryptorProvider;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
-import org.bouncycastle.pkcs.PKCSException;
-
-/**
- * Utilities around private keys and certificate, mostly wrapping BouncyCastle
- * implementations.
- */
-class PkiUtils {
- final static String PKCS12 = "PKCS12";
-
- private final static String SECURITY_PROVIDER;
- static {
- Security.addProvider(new BouncyCastleProvider());
- SECURITY_PROVIDER = "BC";
- }
-
- public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal,
- int keySize, char[] keyPassword) {
- try {
- KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
- kpGen.initialize(keySize, new SecureRandom());
- KeyPair pair = kpGen.generateKeyPair();
- Date notBefore = new Date(System.currentTimeMillis() - 10000);
- Date notAfter = new Date(System.currentTimeMillis() + 365 * 24L * 3600 * 1000);
- BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
- X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(x500Principal, serial, notBefore,
- notAfter, x500Principal, pair.getPublic());
- ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
- .build(pair.getPrivate());
- X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
- .getCertificate(certGen.build(sigGen));
- cert.checkValidity(new Date());
- cert.verify(cert.getPublicKey());
-
- keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(), keyPassword, new Certificate[] { cert });
- return cert;
- } catch (GeneralSecurityException | OperatorCreationException e) {
- throw new RuntimeException("Cannot generate self-signed certificate", e);
- }
- }
-
- public static KeyStore getKeyStore(Path keyStoreFile, char[] keyStorePassword, String keyStoreType) {
- try {
- KeyStore store = KeyStore.getInstance(keyStoreType, SECURITY_PROVIDER);
- if (Files.exists(keyStoreFile)) {
- try (InputStream fis = Files.newInputStream(keyStoreFile)) {
- store.load(fis, keyStorePassword);
- }
- } else {
- store.load(null);
- }
- return store;
- } catch (GeneralSecurityException | IOException e) {
- throw new RuntimeException("Cannot load keystore " + keyStoreFile, e);
- }
- }
-
- public static void saveKeyStore(Path keyStoreFile, char[] keyStorePassword, KeyStore keyStore) {
- try {
- try (OutputStream fis = Files.newOutputStream(keyStoreFile)) {
- keyStore.store(fis, keyStorePassword);
- }
- } catch (GeneralSecurityException | IOException e) {
- throw new RuntimeException("Cannot save keystore " + keyStoreFile, e);
- }
- }
-
-// public static byte[] pemToPKCS12(final String keyFile, final String cerFile, final String password)
-// throws Exception {
-// // Get the private key
-// FileReader reader = new FileReader(keyFile);
-//
-// PEMReader pem = new PemReader(reader, new PasswordFinder() {
-// @Override
-// public char[] getPassword() {
-// return password.toCharArray();
-// }
-// });
-//
-// PrivateKey key = ((KeyPair) pem.readObject()).getPrivate();
-//
-// pem.close();
-// reader.close();
-//
-// // Get the certificate
-// reader = new FileReader(cerFile);
-// pem = new PEMReader(reader);
-//
-// X509Certificate cert = (X509Certificate) pem.readObject();
-//
-// pem.close();
-// reader.close();
-//
-// // Put them into a PKCS12 keystore and write it to a byte[]
-// ByteArrayOutputStream bos = new ByteArrayOutputStream();
-// KeyStore ks = KeyStore.getInstance("PKCS12");
-// ks.load(null);
-// ks.setKeyEntry("alias", (Key) key, password.toCharArray(), new java.security.cert.Certificate[] { cert });
-// ks.store(bos, password.toCharArray());
-// bos.close();
-// return bos.toByteArray();
-// }
-
- public static void loadPem(KeyStore keyStore, Reader key, char[] keyPassword, Reader cert) {
- PrivateKey privateKey = loadPemPrivateKey(key, keyPassword);
- X509Certificate certificate = loadPemCertificate(cert);
- try {
- keyStore.setKeyEntry(certificate.getSubjectX500Principal().getName(), privateKey, keyPassword,
- new java.security.cert.Certificate[] { certificate });
- } catch (KeyStoreException e) {
- throw new RuntimeException("Cannot store PEM certificate", e);
- }
- }
-
- public static PrivateKey loadPemPrivateKey(Reader reader, char[] keyPassword) {
- try (PEMParser pemParser = new PEMParser(reader)) {
- JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
- Object object = pemParser.readObject();
- PrivateKeyInfo privateKeyInfo;
- if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
- if (keyPassword == null)
- throw new IllegalArgumentException("A key password is required");
- InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword);
- privateKeyInfo = ((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv);
- } else if (object instanceof PrivateKeyInfo) {
- privateKeyInfo = (PrivateKeyInfo) object;
- } else {
- throw new IllegalArgumentException("Unsupported format for private key");
- }
- return converter.getPrivateKey(privateKeyInfo);
- } catch (IOException | OperatorCreationException | PKCSException e) {
- throw new RuntimeException("Cannot read private key", e);
- }
- }
-
- public static X509Certificate loadPemCertificate(Reader reader) {
- try (PEMParser pemParser = new PEMParser(reader)) {
- X509CertificateHolder certHolder = (X509CertificateHolder) pemParser.readObject();
- X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
- .getCertificate(certHolder);
- return cert;
- } catch (IOException | CertificateException e) {
- throw new RuntimeException("Cannot read private key", e);
- }
- }
-
- public static void main(String[] args) throws Exception {
- final String ALGORITHM = "RSA";
- final String provider = "BC";
- SecureRandom secureRandom = new SecureRandom();
- long begin = System.currentTimeMillis();
- for (int i = 512; i < 1024; i = i + 2) {
- try {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM, provider);
- keyGen.initialize(i, secureRandom);
- keyGen.generateKeyPair();
- } catch (Exception e) {
- System.err.println(i + " : " + e.getMessage());
- }
- }
- System.out.println((System.currentTimeMillis() - begin) + " ms");
-
- // // String text = "a";
- // String text =
- // "testtesttesttesttesttesttesttesttesttesttesttesttesttesttest";
- // try {
- // System.out.println(text);
- // PrivateKey privateKey;
- // PublicKey publicKey;
- // char[] password = "changeit".toCharArray();
- // String alias = "CN=test";
- // KeyStore keyStore = KeyStore.getInstance("pkcs12");
- // File p12file = new File("test.p12");
- // p12file.delete();
- // if (!p12file.exists()) {
- // keyStore.load(null);
- // generateSelfSignedCertificate(keyStore, new X500Principal(alias),
- // 513, password);
- // try (OutputStream out = new FileOutputStream(p12file)) {
- // keyStore.store(out, password);
- // }
- // }
- // try (InputStream in = new FileInputStream(p12file)) {
- // keyStore.load(in, password);
- // privateKey = (PrivateKey) keyStore.getKey(alias, password);
- // publicKey = keyStore.getCertificateChain(alias)[0].getPublicKey();
- // }
- // // KeyPair key;
- // // final KeyPairGenerator keyGen =
- // // KeyPairGenerator.getInstance(ALGORITHM);
- // // keyGen.initialize(4096, new SecureRandom());
- // // long begin = System.currentTimeMillis();
- // // key = keyGen.generateKeyPair();
- // // System.out.println((System.currentTimeMillis() - begin) + " ms");
- // // keyStore.load(null);
- // // keyStore.setKeyEntry("test", key.getPrivate(), password, null);
- // // try(OutputStream out=new FileOutputStream(p12file)) {
- // // keyStore.store(out, password);
- // // }
- // // privateKey = key.getPrivate();
- // // publicKey = key.getPublic();
- //
- // Cipher encrypt = Cipher.getInstance(ALGORITHM);
- // encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
- // byte[] encrypted = encrypt.doFinal(text.getBytes());
- // String encryptedBase64 =
- // Base64.getEncoder().encodeToString(encrypted);
- // System.out.println(encryptedBase64);
- // byte[] encryptedFromBase64 =
- // Base64.getDecoder().decode(encryptedBase64);
- //
- // Cipher decrypt = Cipher.getInstance(ALGORITHM);
- // decrypt.init(Cipher.DECRYPT_MODE, privateKey);
- // byte[] decrypted = decrypt.doFinal(encryptedFromBase64);
- // System.out.println(new String(decrypted));
- // } catch (Exception e) {
- // e.printStackTrace();
- // }
-
- }
-
-}
.build(register);
// Deployment Configuration
- DeployConfig deployConfig = new DeployConfig();
- Component<DeployConfig> deployConfigC = new Component.Builder<>(deployConfig) //
- .addType(DeployConfig.class) //
- .addActivation(deployConfig::start) //
- .addDeactivation(deployConfig::stop) //
- .build(register);
+// DeployConfig deployConfig = new DeployConfig();
+// Component<DeployConfig> deployConfigC = new Component.Builder<>(deployConfig) //
+// .addType(DeployConfig.class) //
+// .addActivation(deployConfig::start) //
+// .addDeactivation(deployConfig::stop) //
+// .build(register);
// CMS Deployment
CmsDeploymentImpl cmsDeployment = new CmsDeploymentImpl();
.addActivation(cmsDeployment::start) //
.addDeactivation(cmsDeployment::stop) //
.addDependency(cmsStateC.getType(CmsState.class), cmsDeployment::setCmsState, null) //
- .addDependency(deployConfigC.getType(DeployConfig.class), cmsDeployment::setDeployConfig, null) //
+// .addDependency(deployConfigC.getType(DeployConfig.class), cmsDeployment::setDeployConfig, null) //
.build(register);
// Transaction manager
.addType(UserAdmin.class) //
.addDependency(transactionManagerC.getType(WorkControl.class), userAdmin::setTransactionManager, null) //
.addDependency(transactionManagerC.getType(WorkTransaction.class), userAdmin::setUserTransaction, null) //
- .addDependency(deployConfigC.getType(DeployConfig.class), (d) -> {
- for (Dictionary<String, Object> userDirectoryConfig : d.getUserDirectoryConfigs())
- userAdmin.enableUserDirectory(userDirectoryConfig);
- }, null) //
+// .addDependency(deployConfigC.getType(DeployConfig.class), (d) -> {
+// for (Dictionary<String, Object> userDirectoryConfig : d.getUserDirectoryConfigs())
+// userAdmin.enableUserDirectory(userDirectoryConfig);
+// }, null) //
.build(register);
// User manager
--- /dev/null
+package org.argeo.cms.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.internal.runtime.KernelConstants;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.InputDecryptorProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.bouncycastle.pkcs.PKCSException;
+
+/**
+ * Utilities around private keys and certificate, mostly wrapping BouncyCastle
+ * implementations.
+ */
+public class PkiUtils {
+ private final static CmsLog log = CmsLog.getLog(PkiUtils.class);
+
+ public final static String PKCS12 = "PKCS12";
+ public static final String DEFAULT_KEYSTORE_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".p12";
+
+ public static final String DEFAULT_PEM_KEY_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".key";
+
+ public static final String DEFAULT_PEM_CERT_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".crt";
+
+ private final static String SECURITY_PROVIDER;
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ SECURITY_PROVIDER = "BC";
+ }
+
+ public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal,
+ int keySize, char[] keyPassword) {
+ try {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
+ kpGen.initialize(keySize, new SecureRandom());
+ KeyPair pair = kpGen.generateKeyPair();
+ Date notBefore = new Date(System.currentTimeMillis() - 10000);
+ Date notAfter = new Date(System.currentTimeMillis() + 365 * 24L * 3600 * 1000);
+ BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(x500Principal, serial, notBefore,
+ notAfter, x500Principal, pair.getPublic());
+ ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
+ .build(pair.getPrivate());
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
+ .getCertificate(certGen.build(sigGen));
+ cert.checkValidity(new Date());
+ cert.verify(cert.getPublicKey());
+
+ keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(), keyPassword, new Certificate[] { cert });
+ return cert;
+ } catch (GeneralSecurityException | OperatorCreationException e) {
+ throw new RuntimeException("Cannot generate self-signed certificate", e);
+ }
+ }
+
+ public static KeyStore getKeyStore(Path keyStoreFile, char[] keyStorePassword, String keyStoreType) {
+ try {
+ KeyStore store = KeyStore.getInstance(keyStoreType, SECURITY_PROVIDER);
+ if (Files.exists(keyStoreFile)) {
+ try (InputStream fis = Files.newInputStream(keyStoreFile)) {
+ store.load(fis, keyStorePassword);
+ }
+ } else {
+ store.load(null);
+ }
+ return store;
+ } catch (GeneralSecurityException | IOException e) {
+ throw new RuntimeException("Cannot load keystore " + keyStoreFile, e);
+ }
+ }
+
+ public static void saveKeyStore(Path keyStoreFile, char[] keyStorePassword, KeyStore keyStore) {
+ try {
+ try (OutputStream fis = Files.newOutputStream(keyStoreFile)) {
+ keyStore.store(fis, keyStorePassword);
+ }
+ } catch (GeneralSecurityException | IOException e) {
+ throw new RuntimeException("Cannot save keystore " + keyStoreFile, e);
+ }
+ }
+
+// public static byte[] pemToPKCS12(final String keyFile, final String cerFile, final String password)
+// throws Exception {
+// // Get the private key
+// FileReader reader = new FileReader(keyFile);
+//
+// PEMReader pem = new PemReader(reader, new PasswordFinder() {
+// @Override
+// public char[] getPassword() {
+// return password.toCharArray();
+// }
+// });
+//
+// PrivateKey key = ((KeyPair) pem.readObject()).getPrivate();
+//
+// pem.close();
+// reader.close();
+//
+// // Get the certificate
+// reader = new FileReader(cerFile);
+// pem = new PEMReader(reader);
+//
+// X509Certificate cert = (X509Certificate) pem.readObject();
+//
+// pem.close();
+// reader.close();
+//
+// // Put them into a PKCS12 keystore and write it to a byte[]
+// ByteArrayOutputStream bos = new ByteArrayOutputStream();
+// KeyStore ks = KeyStore.getInstance("PKCS12");
+// ks.load(null);
+// ks.setKeyEntry("alias", (Key) key, password.toCharArray(), new java.security.cert.Certificate[] { cert });
+// ks.store(bos, password.toCharArray());
+// bos.close();
+// return bos.toByteArray();
+// }
+
+ public static void loadPem(KeyStore keyStore, Reader key, char[] keyPassword, Reader cert) {
+ PrivateKey privateKey = loadPemPrivateKey(key, keyPassword);
+ X509Certificate certificate = loadPemCertificate(cert);
+ try {
+ keyStore.setKeyEntry(certificate.getSubjectX500Principal().getName(), privateKey, keyPassword,
+ new java.security.cert.Certificate[] { certificate });
+ } catch (KeyStoreException e) {
+ throw new RuntimeException("Cannot store PEM certificate", e);
+ }
+ }
+
+ public static PrivateKey loadPemPrivateKey(Reader reader, char[] keyPassword) {
+ try (PEMParser pemParser = new PEMParser(reader)) {
+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
+ Object object = pemParser.readObject();
+ PrivateKeyInfo privateKeyInfo;
+ if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
+ if (keyPassword == null)
+ throw new IllegalArgumentException("A key password is required");
+ InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword);
+ privateKeyInfo = ((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv);
+ } else if (object instanceof PrivateKeyInfo) {
+ privateKeyInfo = (PrivateKeyInfo) object;
+ } else {
+ throw new IllegalArgumentException("Unsupported format for private key");
+ }
+ return converter.getPrivateKey(privateKeyInfo);
+ } catch (IOException | OperatorCreationException | PKCSException e) {
+ throw new RuntimeException("Cannot read private key", e);
+ }
+ }
+
+ public static X509Certificate loadPemCertificate(Reader reader) {
+ try (PEMParser pemParser = new PEMParser(reader)) {
+ X509CertificateHolder certHolder = (X509CertificateHolder) pemParser.readObject();
+ X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
+ .getCertificate(certHolder);
+ return cert;
+ } catch (IOException | CertificateException e) {
+ throw new RuntimeException("Cannot read private key", e);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final String ALGORITHM = "RSA";
+ final String provider = "BC";
+ SecureRandom secureRandom = new SecureRandom();
+ long begin = System.currentTimeMillis();
+ for (int i = 512; i < 1024; i = i + 2) {
+ try {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM, provider);
+ keyGen.initialize(i, secureRandom);
+ keyGen.generateKeyPair();
+ } catch (Exception e) {
+ System.err.println(i + " : " + e.getMessage());
+ }
+ }
+ System.out.println((System.currentTimeMillis() - begin) + " ms");
+
+ // // String text = "a";
+ // String text =
+ // "testtesttesttesttesttesttesttesttesttesttesttesttesttesttest";
+ // try {
+ // System.out.println(text);
+ // PrivateKey privateKey;
+ // PublicKey publicKey;
+ // char[] password = "changeit".toCharArray();
+ // String alias = "CN=test";
+ // KeyStore keyStore = KeyStore.getInstance("pkcs12");
+ // File p12file = new File("test.p12");
+ // p12file.delete();
+ // if (!p12file.exists()) {
+ // keyStore.load(null);
+ // generateSelfSignedCertificate(keyStore, new X500Principal(alias),
+ // 513, password);
+ // try (OutputStream out = new FileOutputStream(p12file)) {
+ // keyStore.store(out, password);
+ // }
+ // }
+ // try (InputStream in = new FileInputStream(p12file)) {
+ // keyStore.load(in, password);
+ // privateKey = (PrivateKey) keyStore.getKey(alias, password);
+ // publicKey = keyStore.getCertificateChain(alias)[0].getPublicKey();
+ // }
+ // // KeyPair key;
+ // // final KeyPairGenerator keyGen =
+ // // KeyPairGenerator.getInstance(ALGORITHM);
+ // // keyGen.initialize(4096, new SecureRandom());
+ // // long begin = System.currentTimeMillis();
+ // // key = keyGen.generateKeyPair();
+ // // System.out.println((System.currentTimeMillis() - begin) + " ms");
+ // // keyStore.load(null);
+ // // keyStore.setKeyEntry("test", key.getPrivate(), password, null);
+ // // try(OutputStream out=new FileOutputStream(p12file)) {
+ // // keyStore.store(out, password);
+ // // }
+ // // privateKey = key.getPrivate();
+ // // publicKey = key.getPublic();
+ //
+ // Cipher encrypt = Cipher.getInstance(ALGORITHM);
+ // encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
+ // byte[] encrypted = encrypt.doFinal(text.getBytes());
+ // String encryptedBase64 =
+ // Base64.getEncoder().encodeToString(encrypted);
+ // System.out.println(encryptedBase64);
+ // byte[] encryptedFromBase64 =
+ // Base64.getDecoder().decode(encryptedBase64);
+ //
+ // Cipher decrypt = Cipher.getInstance(ALGORITHM);
+ // decrypt.init(Cipher.DECRYPT_MODE, privateKey);
+ // byte[] decrypted = decrypt.doFinal(encryptedFromBase64);
+ // System.out.println(new String(decrypted));
+ // } catch (Exception e) {
+ // e.printStackTrace();
+ // }
+
+ }
+
+ public static void createSelfSignedKeyStore(Path keyStorePath, char[] keyStorePassword, String keyStoreType) {
+ // for (Provider provider : Security.getProviders())
+ // System.out.println(provider.getName());
+ // File keyStoreFile = keyStorePath.toFile();
+ char[] keyPwd = Arrays.copyOf(keyStorePassword, keyStorePassword.length);
+ if (!Files.exists(keyStorePath)) {
+ try {
+ Files.createDirectories(keyStorePath.getParent());
+ KeyStore keyStore = getKeyStore(keyStorePath, keyStorePassword, keyStoreType);
+ generateSelfSignedCertificate(keyStore,
+ new X500Principal("CN=" + InetAddress.getLocalHost().getHostName() + ",OU=UNSECURE,O=UNSECURE"),
+ 1024, keyPwd);
+ saveKeyStore(keyStorePath, keyStorePassword, keyStore);
+ if (log.isDebugEnabled())
+ log.debug("Created self-signed unsecure keystore " + keyStorePath);
+ } catch (Exception e) {
+ try {
+ if (Files.size(keyStorePath) == 0)
+ Files.delete(keyStorePath);
+ } catch (IOException e1) {
+ // silent
+ }
+ log.error("Cannot create keystore " + keyStorePath, e);
+ }
+ } else {
+ throw new IllegalStateException("Keystore " + keyStorePath + " already exists");
+ }
+ }
+
+}
// return res;
// }
- public void destroy() {
+ public void start() {
+
+ }
+
+ public void stop() {
for (LdapName name : businessRoles.keySet()) {
DirectoryUserAdmin userDirectory = businessRoles.get(name);
destroy(userDirectory);
userDirectory.destroy();
}
+// protected void removeUserDirectory(UserDirectory userDirectory) {
+// LdapName baseDn = toLdapName(userDirectory.getContext());
+// businessRoles.remove(baseDn);
+// if (userDirectory instanceof DirectoryUserAdmin)
+// destroy((DirectoryUserAdmin) userDirectory);
+// }
+
+ @Deprecated
protected void removeUserDirectory(String basePath) {
if (isSystemRolesBaseDn(basePath))
throw new IllegalArgumentException("System roles cannot be removed ");
public Set<UserDirectory> getUserDirectories() {
TreeSet<UserDirectory> res = new TreeSet<>((o1, o2) -> o1.getContext().compareTo(o2.getContext()));
res.addAll(businessRoles.values());
+ res.add(systemRoles);
return res;
}
+
}