Skip to content

Commit

Permalink
add security and integration check with RSA
Browse files Browse the repository at this point in the history
  • Loading branch information
elguardian committed Mar 14, 2024
1 parent 8b0d55e commit 64a821a
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public class KieServerConstants {
public static final String CFG_KIE_USER = "org.kie.server.user";
public static final String CFG_KIE_PASSWORD = "org.kie.server.pwd";
public static final String CFG_KIE_TOKEN = "org.kie.server.token";
public static final String CFG_KIE_ISSUER = "org.kie.server.issuer";

/**
* Security settings used to connect to KIE Server Controller
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
package org.kie.server.common;

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.util.HashSet;
import java.util.Set;

import org.drools.core.util.KeyStoreConstants;
import org.drools.core.util.KeyStoreHelper;
import org.kie.server.api.KieServerConstants;
import org.kie.server.api.model.KieServerConfig;
Expand All @@ -16,7 +26,10 @@ public class KeyStoreHelperUtil {
private static final String PROP_PWD_SERVER_PWD = "kie.keystore.key.server.pwd";

// the private key identifier for controller
private static final String PROP_PWD_CTRL_ALIAS = "kie.keystore.key.ctrl.alias";
public static final String PROP_PWD_JWT_ALIAS = "kie.keystore.key.jwt.alias";

// the private key identifier for controller
private static final String PROP_PWD_CTRL_ALIAS = "kie.keystore.key.ctrl.alias";
// the private key identifier for controller
private static final String PROP_PWD_CTRL_PWD = "kie.keystore.key.ctrl.pwd";

Expand All @@ -37,6 +50,30 @@ public static String loadControllerPassword(final String defaultPassword) {
return loadPasswordKey(PROP_PWD_CTRL_ALIAS, PROP_PWD_CTRL_PWD, defaultPassword);
}

public static KeyPair getJwtKeyPair() {
String pwdKeyAlias = System.getProperty(PROP_PWD_JWT_ALIAS, "");
String pwdKeyPassword = System.getProperty(KeyStoreConstants.PROP_PVT_KS_PWD, "");
return getJwtKeyPair(pwdKeyAlias, pwdKeyPassword);
}

public static KeyPair getJwtKeyPair(String pwdKeyAlias, String pwdKeyPassword) {
try {
KeyStoreHelper keyStoreHelper = KeyStoreHelper.get();
KeyStore keystore = keyStoreHelper.getPvtKeyStore();
Key key = (PrivateKey) keystore.getKey(pwdKeyAlias, pwdKeyPassword.toCharArray());
if (key instanceof PrivateKey) {
// Get certificate of public key
Certificate cert = keystore.getCertificate(pwdKeyAlias);
PublicKey publicKey = cert.getPublicKey();
return new KeyPair(publicKey, (PrivateKey) key);
}
return null;
} catch (RuntimeException | UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException re) {
logger.warn("Unable to load key store. Using password from configuration");
}
return null;
}

public static String loadPasswordKey(String pwdKeyAliasProperty, String pwdKeyPasswordProperty, String defaultPassword) {
String passwordKey;
KeyStoreHelper keyStoreHelper = KeyStoreHelper.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,83 @@

package org.kie.server.common;

import java.net.URI;
import java.nio.file.Paths;

import org.drools.core.util.KeyStoreConstants;
import org.drools.core.util.KeyStoreHelper;
import org.junit.BeforeClass;
import org.junit.Test;
import org.kie.server.api.KieServerConstants;
import org.kie.server.api.model.KieServerConfig;
import org.kie.server.api.model.KieServerConfigItem;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.kie.server.common.KeyStoreHelperUtil.loadControllerPassword;

public class KeyStoreHelperUtilTest {

private static final String KEYSTORE_PATH = "target/keystore.jks";
private static final String KEYSTORE_PWD = "password";
private static final String KEYSTORE_ALIAS = "selfsigned";

@BeforeClass
public static void init() throws Exception {
// generate self signed certificate
String[] cmd = { "keytool", "-genkey",
"-keyalg", "RSA",
"-alias", KEYSTORE_ALIAS,
"-keystore", KEYSTORE_PATH,
"-storepass", KEYSTORE_PWD,
"-validity", "360",
"-keysize", "1024",
"-dname", "CN=root, OU=root, O=root, L=root, ST=root, C=root"
};

ProcessBuilder builder = new ProcessBuilder();
builder.command(cmd);
Process p = builder.start();
p.waitFor();
}

@Test
public void testKeyPairReading() throws Exception {
try {
// this test if we can read our own keys properly
URI uri = Paths.get(KEYSTORE_PATH).toAbsolutePath().toUri();
System.setProperty(KeyStoreConstants.PROP_PVT_KS_URL, uri.toURL().toExternalForm());
System.setProperty(KeyStoreConstants.PROP_PVT_KS_PWD, KEYSTORE_PWD);
System.setProperty(KeyStoreHelperUtil.PROP_PWD_JWT_ALIAS, KEYSTORE_ALIAS);

KeyStoreHelper.reInit();

assertNotNull(KeyStoreHelperUtil.getJwtKeyPair());

} finally {
System.clearProperty(KeyStoreConstants.PROP_PVT_KS_URL);
System.clearProperty(KeyStoreConstants.PROP_PVT_KS_PWD);
System.clearProperty(KeyStoreHelperUtil.PROP_PWD_JWT_ALIAS);
}

}

@Test
public void testDefaultPassword(){
public void testDefaultPassword() {
final String defaultPassword = "default";
final String password = loadControllerPassword(defaultPassword);
assertEquals(defaultPassword, password);
}

@Test
public void testConfigDefaultPassword(){
public void testConfigDefaultPassword() {
final KieServerConfig serverConfig = new KieServerConfig();
final String password = loadControllerPassword(serverConfig);
assertEquals("kieserver1!", password);
}

@Test
public void testConfigPassword(){
public void testConfigPassword() {
final KieServerConfig serverConfig = new KieServerConfig();
final String defaultPassword = "default";
serverConfig.addConfigItem(new KieServerConfigItem(KieServerConstants.CFG_KIE_CONTROLLER_PASSWORD, defaultPassword, null));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

package org.kie.server.services.impl.util;

import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
Expand Down Expand Up @@ -55,7 +56,7 @@ public String getIssuer() {
return issuer;
}

public String token(String user, String ...roles) {
public String token(String user, String... roles) {
return JWT.create().withIssuer(this.issuer).withSubject(user).withClaim("roles", Arrays.asList(roles)).sign(algorithm);
}

Expand All @@ -81,6 +82,13 @@ public JwtService build() {
return new JwtService(algorithm != null ? algorithm : Algorithm.none(), issuer != null ? issuer : "jBPM");
}

public JwtServiceBuilder keyPair(KeyPair keyPair) {
if (keyPair != null) {
this.algorithm = Algorithm.RSA256((RSAPublicKey) keyPair.getPublic(), (RSAPrivateKey) keyPair.getPrivate());
}
return this;
}

}

public JwtUserDetails decodeUserDetails(String token) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
org.kie.server.services.impl.security.adapters.TomcatSecurityAdapter
org.kie.server.services.impl.security.adapters.JMSSecurityAdapter
org.kie.server.services.impl.security.adapters.BrokerSecurityAdapter
org.kie.server.services.impl.security.adapters.WeblogicSecurityAdapter
org.kie.server.services.impl.security.adapters.WebSphereSecurityAdapter
org.kie.server.services.impl.security.adapters.JwtSecurityAdaptor
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
org.kie.server.services.jbpm.security.JMSUserGroupAdapter
org.kie.server.services.jbpm.security.BrokerUserGroupAdapter
org.kie.server.services.jbpm.security.TomcatUserGroupAdapter
org.kie.server.services.jbpm.security.ElytronUserGroupAdapter
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.kie.server.services.jbpm.kafka;

import java.io.IOException;
import java.security.KeyPair;
import java.time.Duration;
import java.util.Map;
import java.util.Set;
Expand All @@ -38,7 +39,9 @@
import org.jbpm.services.api.model.MessageDesc;
import org.jbpm.services.api.model.SignalDesc;
import org.jbpm.services.api.model.SignalDescBase;
import org.kie.server.api.KieServerConstants;
import org.kie.server.api.jms.JMSConstants;
import org.kie.server.common.KeyStoreHelperUtil;
import org.kie.server.services.impl.security.adapters.JwtSecurityAdaptor;
import org.kie.server.services.impl.util.JwtService;
import org.kie.server.services.impl.security.adapters.BrokerSecurityAdapter;
Expand Down Expand Up @@ -77,7 +80,11 @@ public KafkaServerConsumer(KafkaEventProcessorFactory factory, Supplier<Consumer
this.factory = factory;
this.consumerSupplier = consumerSupplier;
this.processService = processService;
this.jwtService = JwtService.newJwtServiceBuilder().build();
KeyPair keyPair = KeyStoreHelperUtil.getJwtKeyPair();
this.jwtService = JwtService.newJwtServiceBuilder()
.keyPair(keyPair)
.issuer(System.getProperty(KieServerConstants.CFG_KIE_ISSUER, "jBPM"))
.build();
}

void addRegistration(DeploymentEvent event) {
Expand Down Expand Up @@ -239,7 +246,7 @@ private void processMessage(ConsumerRecord<String, byte[]> event,
}

private String getValue(Header header) {
return header != null && header.value() != null ? new String(header.value()) : "";
return header != null && header.value() != null ? new String(header.value()) : null;
}

private void processEvent(ConsumerRecord<String, byte[]> event,
Expand All @@ -249,17 +256,23 @@ private void processEvent(ConsumerRecord<String, byte[]> event,

String username = getValue(event.headers().lastHeader(USER_PROPERTY_NAME));
String password = getValue(event.headers().lastHeader(PASSWRD_PROPERTY_NAME));
String token = getValue(event.headers().lastHeader(JMSConstants.ASSERTION_PROPERTY_NAME));

if (username != null && password != null) {
BrokerSecurityAdapter.login(username, password);
} else {
logger.debug("Unable to login to JMSSecurityAdapter, user name and/or password missing for user{}", username);
logger.debug("Unable to login to BrokerSecurityAdapter, user name and/or password missing for user{}", username);
}

try {
if (token != null) {
String token = getValue(event.headers().lastHeader(JMSConstants.ASSERTION_PROPERTY_NAME));
if (token != null) {
try {
JwtSecurityAdaptor.login(jwtService.decodeUserDetails(token));
}
}catch (IllegalArgumentException e) {
logger.debug("Unable to login to JwtSecurityAdaptor, user name and/or password missing for token {}", token, e);
}
}

try {
String signalName = signal.getName();
ClassLoader cl = classLoaders.get(deploymentId);
Class<?> valueType = Object.class;
Expand All @@ -276,12 +289,12 @@ private void processEvent(ConsumerRecord<String, byte[]> event,
deploymentId, value);
} catch (ClassNotFoundException ex) {
logger.error("Class not found in deployment id {}", deploymentId, ex);
} catch (IllegalArgumentException e) {
logger.error("Exception token login {}", token, e);
} catch (RuntimeException | IOException ex) {
logger.error("Exception deserializing event", ex);
} finally {
JwtSecurityAdaptor.logout();
if (token != null) {
JwtSecurityAdaptor.logout();
}
}
}
}

0 comments on commit 64a821a

Please sign in to comment.