Skip to content

Commit 8918545

Browse files
authored
Merge pull request #3417 from akto-api-security/fix/login_session_by_key_pairs
Fix/login session by key pairs
2 parents 8849aa7 + 8cccf56 commit 8918545

File tree

4 files changed

+181
-11
lines changed

4 files changed

+181
-11
lines changed

apps/dashboard/src/main/java/com/akto/listener/InitializerListener.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@
217217
import com.akto.util.tasks.OrganizationTask;
218218
import com.akto.utils.Auth0;
219219
import com.akto.utils.AutomatedApiGroupsUtils;
220+
import com.akto.utils.RSAKeyPairUtils;
220221
import com.akto.utils.TestTemplateUtils;
221222
import com.akto.utils.billing.OrganizationUtils;
222223
import com.akto.utils.crons.Crons;

libs/dao/src/main/java/com/akto/dto/Config.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public void setId(String id) {
3737
public String id;
3838

3939
public enum ConfigType {
40-
SLACK, GOOGLE, WEBPUSH, PASSWORD, SALESFORCE, SENDGRID, AUTH0, GITHUB, STIGG, MIXPANEL, SLACK_ALERT, OKTA, AZURE, HYBRID_SAAS, SLACK_ALERT_USAGE, GOOGLE_SAML, AWS_WAF, SPLUNK_SIEM, AKTO_DASHBOARD_HOST_URL, CLOUDFLARE_WAF;
40+
SLACK, GOOGLE, WEBPUSH, PASSWORD, SALESFORCE, SENDGRID, AUTH0, GITHUB, STIGG, MIXPANEL, SLACK_ALERT, OKTA, AZURE, HYBRID_SAAS, SLACK_ALERT_USAGE, GOOGLE_SAML, AWS_WAF, SPLUNK_SIEM, AKTO_DASHBOARD_HOST_URL, CLOUDFLARE_WAF, RSA_KP;
4141
}
4242

4343
public ConfigType configType;
@@ -938,6 +938,40 @@ public AktoHostUrlConfig() {
938938
}
939939
}
940940

941+
@Getter
942+
@Setter
943+
@BsonDiscriminator
944+
public static class RSAKeyPairConfig extends Config {
945+
946+
public static final String PRIVATE_KEY = "privateKey";
947+
public static final String PUBLIC_KEY = "publicKey";
948+
public static final String CREATED_AT = "createdAt";
949+
950+
private String privateKey;
951+
private String publicKey;
952+
private int createdAt;
953+
954+
public RSAKeyPairConfig() {
955+
this.configType = ConfigType.RSA_KP;
956+
this.id = ConfigType.RSA_KP.name() + CONFIG_SALT;
957+
}
958+
959+
public RSAKeyPairConfig(String privateKey, String publicKey) {
960+
this.configType = ConfigType.RSA_KP;
961+
this.id = ConfigType.RSA_KP.name() + CONFIG_SALT;
962+
this.privateKey = privateKey;
963+
this.publicKey = publicKey;
964+
}
965+
966+
public RSAKeyPairConfig(String privateKey, String publicKey, int createdAt) {
967+
this.configType = ConfigType.RSA_KP;
968+
this.id = ConfigType.RSA_KP.name() + CONFIG_SALT;
969+
this.privateKey = privateKey;
970+
this.publicKey = publicKey;
971+
this.createdAt = createdAt;
972+
}
973+
}
974+
941975
public static boolean isConfigSSOType(ConfigType configType){
942976
if(configType == null){
943977
return false;

libs/utils/src/main/java/com/akto/onprem/Constants.java

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.akto.onprem;
22

3+
import com.akto.DaoInit;
34
import com.akto.dao.ConfigsDao;
5+
import com.akto.dao.MCollection;
46
import com.akto.dao.context.Context;
57
import com.akto.dto.Config;
68
import com.akto.util.DashboardMode;
9+
import com.akto.utils.RSAKeyPairUtils;
10+
import com.mongodb.ConnectionString;
711
import com.mongodb.client.model.Filters;
812

913
import java.security.KeyPair;
@@ -28,22 +32,72 @@ public class Constants {
2832

2933
public static final String SLACK_ALERT_USAGE_URL = "";
3034

31-
private static final byte[] privateKey, publicKey;
35+
private static final byte[] privateKey;
36+
private static final byte[] publicKey;
3237

3338
static {
34-
KeyPairGenerator kpg;
35-
KeyPair kp = null;
39+
byte[] tempPrivateKey = null;
40+
byte[] tempPublicKey = null;
41+
42+
// Try to initialize DB connection and fetch keys from database
3643
try {
37-
kpg = KeyPairGenerator.getInstance("RSA");
38-
kpg.initialize(2048);
39-
kp = kpg.generateKeyPair();
44+
// Check if DB client is not already initialized
45+
if (!MCollection.checkConnection()) {
46+
String mongoURI = System.getenv("AKTO_MONGO_CONN");
47+
if (mongoURI != null && !mongoURI.isEmpty()) {
48+
DaoInit.init(new ConnectionString(mongoURI));
49+
}
50+
}
4051

41-
} catch (NoSuchAlgorithmException e) {
42-
;
52+
// Now try to fetch keys if DB is connected
53+
if (MCollection.checkConnection()) {
54+
byte[][] keys = RSAKeyPairUtils.fetchKeysFromDb();
55+
if (keys != null && keys.length == 2) {
56+
tempPrivateKey = keys[0];
57+
tempPublicKey = keys[1];
58+
}
59+
}
60+
} catch (Exception e) {
61+
e.printStackTrace();
62+
}
63+
64+
// If keys weren't found in database, generate new ones and save them
65+
if (tempPrivateKey == null || tempPublicKey == null) {
66+
KeyPairGenerator kpg;
67+
KeyPair kp = null;
68+
try {
69+
kpg = KeyPairGenerator.getInstance("RSA");
70+
kpg.initialize(2048);
71+
kp = kpg.generateKeyPair();
72+
} catch (NoSuchAlgorithmException e) {
73+
;
74+
}
75+
76+
tempPrivateKey = kp == null ? null : kp.getPrivate().getEncoded();
77+
tempPublicKey = kp == null ? null : kp.getPublic().getEncoded();
78+
79+
// Save generated keys to database
80+
if (tempPrivateKey != null && tempPublicKey != null && MCollection.checkConnection()) {
81+
try {
82+
String pemPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
83+
Base64.getEncoder().encodeToString(tempPrivateKey) + "\n" +
84+
"-----END PRIVATE KEY-----";
85+
86+
String pemPublicKey = "-----BEGIN PUBLIC KEY-----\n" +
87+
Base64.getEncoder().encodeToString(tempPublicKey) + "\n" +
88+
"-----END PUBLIC KEY-----";
89+
90+
int now = Context.now();
91+
Config.RSAKeyPairConfig newConfig = new Config.RSAKeyPairConfig(pemPrivateKey, pemPublicKey, now);
92+
ConfigsDao.instance.insertOne(newConfig);
93+
} catch (Exception e) {
94+
e.printStackTrace();
95+
}
96+
}
4397
}
4498

45-
privateKey = kp == null ? null : kp.getPrivate().getEncoded();
46-
publicKey = kp == null ? null : kp.getPublic().getEncoded();
99+
privateKey = tempPrivateKey;
100+
publicKey = tempPublicKey;
47101
}
48102

49103
public static byte[] getPrivateKey() {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.akto.utils;
2+
3+
import java.util.Base64;
4+
5+
import com.akto.dao.ConfigsDao;
6+
import com.akto.dto.Config;
7+
import com.akto.log.LoggerMaker;
8+
import com.akto.log.LoggerMaker.LogDb;
9+
import com.akto.util.Constants;
10+
11+
import static com.akto.dto.Config.CONFIG_SALT;
12+
13+
public class RSAKeyPairUtils {
14+
15+
private static final LoggerMaker logger = new LoggerMaker(RSAKeyPairUtils.class, LogDb.DASHBOARD);
16+
17+
public static byte[] parsePEMPrivateKey(String key) {
18+
String pemKey = key;
19+
byte[] decodedKey;
20+
21+
pemKey = pemKey.replace("-----BEGIN PRIVATE KEY-----","");
22+
pemKey = pemKey.replace("-----END PRIVATE KEY-----","");
23+
pemKey = pemKey.replace("\n","");
24+
25+
decodedKey = Base64.getDecoder().decode(pemKey);
26+
27+
return decodedKey;
28+
}
29+
30+
public static byte[] parsePEMPublicKey(String key) {
31+
String pemKey = key;
32+
byte[] decodedKey;
33+
34+
pemKey = pemKey.replace("-----BEGIN PUBLIC KEY-----","");
35+
pemKey = pemKey.replace("-----END PUBLIC KEY-----","");
36+
pemKey = pemKey.replace("\n","");
37+
38+
decodedKey = Base64.getDecoder().decode(pemKey);
39+
40+
return decodedKey;
41+
}
42+
43+
/**
44+
* Fetches RSA key pair from database and returns them as byte arrays.
45+
* Returns null if keys are not found or if an error occurs.
46+
* This method is called from Constants static block.
47+
*
48+
* @return byte[][] array where [0] is private key and [1] is public key, or null if not found
49+
*/
50+
public static byte[][] fetchKeysFromDb() {
51+
logger.info("Fetching RSA keys from db");
52+
53+
try {
54+
Config.RSAKeyPairConfig rsaKeyPairConfig = (Config.RSAKeyPairConfig) ConfigsDao.instance.findOne(Constants.ID, Config.ConfigType.RSA_KP.name() + CONFIG_SALT);
55+
56+
if (rsaKeyPairConfig != null) {
57+
logger.info("Found RSA keys config in db");
58+
59+
String pemPrivateKey = rsaKeyPairConfig.getPrivateKey();
60+
String pemPublicKey = rsaKeyPairConfig.getPublicKey();
61+
62+
if (pemPrivateKey == null || pemPublicKey == null) {
63+
logger.error("RSA keys not present in config");
64+
return null;
65+
}
66+
67+
byte[] privateKey = RSAKeyPairUtils.parsePEMPrivateKey(pemPrivateKey);
68+
byte[] publicKey = RSAKeyPairUtils.parsePEMPublicKey(pemPublicKey);
69+
70+
logger.info("Successfully fetched RSA keys from db");
71+
return new byte[][] { privateKey, publicKey };
72+
} else {
73+
logger.info("RSA keys config not found in db");
74+
}
75+
} catch (Exception e) {
76+
logger.error("Error while fetching RSA keys from db", e);
77+
}
78+
79+
return null;
80+
}
81+
}

0 commit comments

Comments
 (0)