Browse Source

implemented EncryptedKeyStore

for this to work, the KeyStorage interface had to be extended

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 2 months ago
parent
commit
9ea6148583
  1. 16
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/KeyStorage.java
  2. 14
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  3. 5
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/KeyStoreController.java
  4. 2
      de.srsoftware.oidc.datastore.encrypted/build.gradle
  5. 36
      de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedKeyStore.java
  6. 53
      de.srsoftware.oidc.datastore.encrypted/src/test/java/EncryptedKeyStoreTest.java
  7. 25
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java
  8. 20
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteKeyStore.java
  9. 4
      de.srsoftware.oidc.web/src/main/resources/en/scripts/index.js
  10. 10
      de.srsoftware.oidc.web/src/main/resources/en/todo.html

16
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/KeyStorage.java

@ -3,11 +3,19 @@ package de.srsoftware.oidc.api; @@ -3,11 +3,19 @@ package de.srsoftware.oidc.api;
import java.io.IOException;
import java.util.List;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.lang.JoseException;
public interface KeyStorage {
public KeyStorage drop(String keyId);
public List<String> listKeys();
public PublicJsonWebKey load(String keyId) throws IOException, KeyManager.KeyCreationException;
public KeyStorage store(PublicJsonWebKey jsonWebKey) throws IOException;
public KeyStorage drop(String keyId);
public List<String> listKeys();
public default PublicJsonWebKey load(String keyId) throws IOException, JoseException {
return PublicJsonWebKey.Factory.newPublicJwk(loadJson(keyId));
}
public String loadJson(String keyId) throws IOException;
public KeyStorage store(String keyId, String json) throws IOException;
public default KeyStorage store(PublicJsonWebKey key) throws IOException {
return store(key.getKeyId(), key.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE));
}
}

14
de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java

@ -19,6 +19,7 @@ import de.srsoftware.oidc.api.*; @@ -19,6 +19,7 @@ import de.srsoftware.oidc.api.*;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.oidc.backend.*;
import de.srsoftware.oidc.datastore.encrypted.EncryptedClientService;
import de.srsoftware.oidc.datastore.encrypted.EncryptedKeyStore;
import de.srsoftware.oidc.datastore.encrypted.EncryptedMailConfig;
import de.srsoftware.oidc.datastore.encrypted.EncryptedUserService;
import de.srsoftware.oidc.datastore.file.FileStoreProvider;
@ -153,12 +154,21 @@ public class Application { @@ -153,12 +154,21 @@ public class Application {
private static KeyStorage setupKeyStore(Configuration config, Path defaultConfigDir) throws SQLException {
var keyStorageLocation = new File(config.getOrDefault("key_storage", defaultConfigDir.resolve("keys")));
KeyStorage keyStore = null;
if ((keyStorageLocation.exists() && keyStorageLocation.isDirectory()) || !keyStorageLocation.getName().contains(".")) {
return new PlaintextKeyStore(keyStorageLocation.toPath());
keyStore = new PlaintextKeyStore(keyStorageLocation.toPath());
} else { // SQLite
var conn = connectionProvider.get(keyStorageLocation);
return new SqliteKeyStore(conn);
keyStore = new SqliteKeyStore(conn);
}
Optional<String> encryptionKey = config.get(ENCRYPTION_KEY);
if (encryptionKey.isPresent()){
var salt = config.getOrDefault(SALT,uuid());
keyStore = new EncryptedKeyStore(encryptionKey.get(),salt,keyStore);
}
return keyStore;
}
private static Map<String, Object> map(String[] args) {

5
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/KeyStoreController.java

@ -3,7 +3,6 @@ package de.srsoftware.oidc.backend; @@ -3,7 +3,6 @@ package de.srsoftware.oidc.backend;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.http.PathHandler;
import de.srsoftware.oidc.api.KeyManager;
import de.srsoftware.oidc.api.KeyStorage;
import java.io.IOException;
import org.jose4j.jwk.JsonWebKey;
@ -33,9 +32,7 @@ public class KeyStoreController extends PathHandler { @@ -33,9 +32,7 @@ public class KeyStoreController extends PathHandler {
PublicJsonWebKey key = keyStore.load(keyId);
String keyJson = key.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY);
arr.put(new JSONObject(keyJson));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (KeyManager.KeyCreationException e) {
} catch (Exception e) {
throw new RuntimeException(e);
}
JSONObject result = new JSONObject();

2
de.srsoftware.oidc.datastore.encrypted/build.gradle

@ -16,6 +16,8 @@ dependencies { @@ -16,6 +16,8 @@ dependencies {
implementation 'com.sun.mail:jakarta.mail:2.0.1'
implementation project(':de.srsoftware.utils')
testImplementation project(path: ':de.srsoftware.oidc.api', configuration: "testBundle")
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
}
test {

36
de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedKeyStore.java

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.encrypted;
import de.srsoftware.oidc.api.KeyStorage;
import java.io.IOException;
import java.util.List;
public class EncryptedKeyStore extends EncryptedConfig implements KeyStorage {
private final KeyStorage backend;
public EncryptedKeyStore(String key, String salt, KeyStorage backend) {
super(key, salt);
this.backend = backend;
}
@Override
public KeyStorage drop(String keyId) {
return backend.drop(keyId);
}
@Override
public List<String> listKeys() {
return backend.listKeys();
}
@Override
public String loadJson(String keyId) throws IOException {
return decrypt(backend.loadJson(keyId));
}
@Override
public KeyStorage store(String keyId, String jsonWebKey) throws IOException {
backend.store(keyId, encrypt(jsonWebKey));
return this;
}
}

53
de.srsoftware.oidc.datastore.encrypted/src/test/java/EncryptedKeyStoreTest.java

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
/* © SRSoftware 2024 */
import static de.srsoftware.utils.Strings.uuid;
import de.srsoftware.oidc.api.KeyStorage;
import de.srsoftware.oidc.api.KeyStoreTest;
import de.srsoftware.oidc.datastore.encrypted.EncryptedKeyStore;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
public class EncryptedKeyStoreTest extends KeyStoreTest {
private class InMemoryKeyStore implements KeyStorage {
private HashMap<String, String> store = new HashMap<>();
@Override
public KeyStorage drop(String keyId) {
store.remove(keyId);
return this;
}
@Override
public List<String> listKeys() {
return List.copyOf(store.keySet());
}
@Override
public String loadJson(String keyId) {
return store.get(keyId);
}
@Override
public KeyStorage store(String keyId, String jsonWebKey) throws IOException {
store.put(keyId, jsonWebKey);
return this;
}
}
private KeyStorage keyStore;
@Override
protected KeyStorage keyStore() {
return keyStore;
}
@BeforeEach
public void setup() throws SQLException {
var backend = new InMemoryKeyStore();
var key = uuid();
var salt = uuid();
keyStore = new EncryptedKeyStore(key, salt, backend);
}
}

25
de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/PlaintextKeyStore.java

@ -3,23 +3,19 @@ package de.srsoftware.oidc.datastore.file; @@ -3,23 +3,19 @@ package de.srsoftware.oidc.datastore.file;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
import static org.jose4j.jwk.JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE;
import de.srsoftware.oidc.api.KeyManager;
import de.srsoftware.oidc.api.KeyStorage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.lang.JoseException;
public class PlaintextKeyStore implements KeyStorage {
public static System.Logger LOG = System.getLogger(PlaintextKeyStore.class.getSimpleName());
private final Path dir;
private HashMap<String, PublicJsonWebKey> loaded = new HashMap<>();
private final Path dir;
private HashMap<String, String> loaded = new HashMap<>();
public PlaintextKeyStore(Path storageDir) {
this.dir = storageDir;
@ -42,22 +38,17 @@ public class PlaintextKeyStore implements KeyStorage { @@ -42,22 +38,17 @@ public class PlaintextKeyStore implements KeyStorage {
}
@Override
public PublicJsonWebKey load(String keyId) throws IOException, KeyManager.KeyCreationException {
public String loadJson(String keyId) throws IOException {
var key = loaded.get(keyId);
if (key != null) return key;
var json = Files.readString(filename(keyId));
try {
key = PublicJsonWebKey.Factory.newPublicJwk(json);
loaded.put(keyId, key);
return key;
} catch (JoseException e) {
throw new KeyManager.KeyCreationException(e);
}
key = Files.readString(filename(keyId));
loaded.put(keyId, key);
return key;
}
@Override
public KeyStorage store(PublicJsonWebKey jsonWebKey) throws IOException {
Files.writeString(filename(jsonWebKey.getKeyId()), jsonWebKey.toJson(INCLUDE_PRIVATE));
public KeyStorage store(String keyId, String jsonWebKey) throws IOException {
Files.writeString(filename(keyId), jsonWebKey);
return this;
}

20
de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteKeyStore.java

@ -2,9 +2,6 @@ @@ -2,9 +2,6 @@
package de.srsoftware.oidc.datastore.sqlite;
import static org.jose4j.jwk.JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE;
import de.srsoftware.oidc.api.KeyManager;
import de.srsoftware.oidc.api.KeyStorage;
import java.io.IOException;
import java.sql.Connection;
@ -13,7 +10,6 @@ import java.util.ArrayList; @@ -13,7 +10,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.jose4j.jwk.PublicJsonWebKey;
import org.jose4j.lang.JoseException;
public class SqliteKeyStore extends SqliteStore implements KeyStorage {
private static final String STORE_VERSION = "key_store_version";
@ -99,30 +95,24 @@ public class SqliteKeyStore extends SqliteStore implements KeyStorage { @@ -99,30 +95,24 @@ public class SqliteKeyStore extends SqliteStore implements KeyStorage {
}
@Override
public PublicJsonWebKey load(String keyId) throws IOException, KeyManager.KeyCreationException {
public String loadJson(String keyId) throws IOException {
try {
var stmt = conn.prepareStatement(LOAD_KEY);
stmt.setString(1, keyId);
var rs = stmt.executeQuery();
String json = null;
if (rs.next()) {
json = rs.getString(1);
}
if (rs.next()) json = rs.getString(1);
rs.close();
return PublicJsonWebKey.Factory.newPublicJwk(json);
} catch (JoseException e) {
throw new KeyManager.KeyCreationException(e);
return json;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public KeyStorage store(PublicJsonWebKey jsonWebKey) throws IOException {
public KeyStorage store(String keyId, String json) throws IOException {
try {
var keyId = jsonWebKey.getKeyId();
var json = jsonWebKey.toJson(INCLUDE_PRIVATE);
var stmt = conn.prepareStatement(SAVE_KEY);
var stmt = conn.prepareStatement(SAVE_KEY);
stmt.setString(1, keyId);
stmt.setString(2, json);
stmt.setString(3, json);

4
de.srsoftware.oidc.web/src/main/resources/en/scripts/index.js

@ -24,4 +24,6 @@ function handleDash(response){ @@ -24,4 +24,6 @@ function handleDash(response){
});
}
fetch(client_controller+"/dash").then(handleDash)
document.addEventListener("DOMContentLoaded", function(event) { // wait until page loaded
fetch(client_controller+"/dash").then(handleDash)
});

10
de.srsoftware.oidc.web/src/main/resources/en/todo.html

@ -14,8 +14,16 @@ @@ -14,8 +14,16 @@
<h1>to do…</h1>
<ul>
<li>implement token refresh</li>
<li>Verschlüsselung im config-File</li>
<li>Configuration im Frontend</li>
<li>
On-Load events: manchmal feuern Requests, die User-Daten benötigen bevor der entsprechende User geladen wurde
<ul>
<li>Settings</li>
<li>Dashboard</li>
<li>Navigation</li>
<li>Clients</li>
</ul>
</li>
</ul>
</div>
</body>

Loading…
Cancel
Save