Browse Source

implemented sqlite keystore

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 3 months ago
parent
commit
e9cc73c270
  1. 5
      de.srsoftware.oidc.app/build.gradle
  2. 17
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  3. 23
      de.srsoftware.oidc.datastore.sqlite/build.gradle
  4. 129
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteKeyStore.java
  5. 1
      settings.gradle

5
de.srsoftware.oidc.app/build.gradle

@ -12,13 +12,16 @@ repositories { @@ -12,13 +12,16 @@ repositories {
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation 'org.xerial:sqlite-jdbc:3.46.0.0'
implementation project(':de.srsoftware.http')
implementation project(':de.srsoftware.logging')
implementation project(':de.srsoftware.oidc.api')
implementation project(':de.srsoftware.oidc.backend')
implementation project(':de.srsoftware.oidc.web')
implementation project(':de.srsoftware.utils')
implementation project(':de.srsoftware.oidc.datastore.file')}
implementation project(':de.srsoftware.oidc.datastore.file')
implementation project(':de.srsoftware.oidc.datastore.sqlite')
}
test {
useJUnitPlatform()

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

@ -21,12 +21,14 @@ import de.srsoftware.oidc.backend.*; @@ -21,12 +21,14 @@ import de.srsoftware.oidc.backend.*;
import de.srsoftware.oidc.datastore.file.FileStore;
import de.srsoftware.oidc.datastore.file.PlaintextKeyStore;
import de.srsoftware.oidc.datastore.file.UuidHasher;
import de.srsoftware.oidc.datastore.sqlite.SqliteKeyStore;
import de.srsoftware.oidc.web.Forward;
import de.srsoftware.oidc.web.StaticPages;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.Executors;
import org.sqlite.SQLiteDataSource;
public class Application {
public static final String API_CLIENT = "/api/client";
@ -55,10 +57,17 @@ public class Application { @@ -55,10 +57,17 @@ public class Application {
var firstHash = passwordHasher.hash(FIRST_USER_PASS, FIRST_UUID);
var firstUser = new User(FIRST_USER, firstHash, FIRST_USER, "%s@internal".formatted(FIRST_USER), FIRST_UUID).add(MANAGE_CLIENTS, MANAGE_SMTP, MANAGE_USERS);
KeyStorage keyStore = new PlaintextKeyStore(keyDir);
KeyManager keyManager = new RotatingKeyManager(keyStore);
FileStore fileStore = new FileStore(storageFile, passwordHasher).init(firstUser);
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
var staticPages = (StaticPages) new StaticPages(basePath).bindPath(STATIC_PATH, FAVICON).on(server);
{ // SQLite
SQLiteDataSource dataSource = new SQLiteDataSource();
var dbFile = storageFile.getParentFile().toPath().resolve("db.sqlite3").toFile();
dataSource.setUrl("jdbc:sqlite:%s".formatted(dbFile));
var conn = dataSource.getConnection();
keyStore = new SqliteKeyStore(conn);
}
KeyManager keyManager = new RotatingKeyManager(keyStore);
FileStore fileStore = new FileStore(storageFile, passwordHasher).init(firstUser);
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
var staticPages = (StaticPages) new StaticPages(basePath).bindPath(STATIC_PATH, FAVICON).on(server);
new Forward(INDEX).bindPath(ROOT).on(server);
new WellKnownController().bindPath(WELL_KNOWN).on(server);
new UserController(fileStore, fileStore, fileStore, staticPages).bindPath(API_USER).on(server);

23
de.srsoftware.oidc.datastore.sqlite/build.gradle

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
plugins {
id 'java'
}
group = 'de.srsoftware'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation project(':de.srsoftware.oidc.api')
implementation project(':de.srsoftware.utils')
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
implementation 'org.xerial:sqlite-jdbc:3.46.0.0'
}
test {
useJUnitPlatform()
}

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

@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
/* © SRSoftware 2024 */
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;
import java.sql.SQLException;
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 implements KeyStorage {
private static final String CREATE_MIGRATION_TABLE = "CREATE TABLE IF NOT EXISTS metainfo(key VARCHAR(255) PRIMARY KEY, value TEXT);";
private static final String SELECT_KEYSTORE_VERSION = "SELECT * FROM metainfo WHERE key = 'key_store_version'";
private static final String SET_KEYSTORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = 'key_store_version'";
private static final String CREATE_KEYSTORE_TABLE = "CREATE TABLE IF NOT EXISTS keystore(key_id VARCHAR(255) PRIMARY KEY, json TEXT NOT NULL);";
private static final String SAVE_KEY = "INSERT INTO keystore(key_id, json) values (?,?) ON CONFLICT(key_id) DO UPDATE SET json = ?";
private static final String SELECT_KEY_IDS = "SELECT key_id FROM keystore";
private static final String LOAD_KEY = "SELECT json FROM keystore WHERE key_id = ?";
private static final String DROP_KEY = "DELETE FROM keystore WHERE key_id = ?";
public static System.Logger LOG = System.getLogger(SqliteKeyStore.class.getSimpleName());
private HashMap<String, PublicJsonWebKey> loaded = new HashMap<>();
private final Connection conn;
public SqliteKeyStore(Connection connection) throws SQLException {
conn = connection;
initTables();
}
private void initTables() throws SQLException {
conn.prepareStatement(CREATE_MIGRATION_TABLE).execute();
var rs = conn.prepareStatement(SELECT_KEYSTORE_VERSION).executeQuery();
int availableVersion = 1;
int lastVersion = 1;
if (rs.next()) {
lastVersion = rs.getInt(1);
}
rs.close();
conn.setAutoCommit(false);
var stmt = conn.prepareStatement(SET_KEYSTORE_VERSION);
for (int version = lastVersion; version <= availableVersion; version++) {
try {
switch (version) {
case 1:
createKeyStoreTables();
}
stmt.setInt(1, version);
stmt.execute();
conn.commit();
} catch (Exception e) {
conn.rollback();
LOG.log(System.Logger.Level.ERROR, "Failed to update at keystore version = {0}", version);
break;
}
}
conn.setAutoCommit(true);
}
private void createKeyStoreTables() throws SQLException {
conn.prepareStatement(CREATE_KEYSTORE_TABLE).execute();
}
@Override
public KeyStorage drop(String keyId) {
try {
var stmt = conn.prepareStatement(DROP_KEY);
stmt.setString(1, keyId);
stmt.execute();
} catch (SQLException e) {
LOG.log(System.Logger.Level.WARNING, "Failed to drop key {0} from database:", keyId, e);
}
return this;
}
@Override
public List<String> listKeys() {
var result = new ArrayList<String>();
try {
var rs = conn.prepareStatement(SELECT_KEY_IDS).executeQuery();
while (rs.next()) result.add(rs.getString(1));
rs.close();
} catch (SQLException e) {
LOG.log(System.Logger.Level.WARNING, "Failed to read key ids from table!");
}
return result;
}
@Override
public PublicJsonWebKey load(String keyId) throws IOException, KeyManager.KeyCreationException {
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);
}
rs.close();
return PublicJsonWebKey.Factory.newPublicJwk(json);
} catch (JoseException e) {
throw new KeyManager.KeyCreationException(e);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public KeyStorage store(PublicJsonWebKey jsonWebKey) throws IOException {
try {
var keyId = jsonWebKey.getKeyId();
var json = jsonWebKey.toJson(INCLUDE_PRIVATE);
var stmt = conn.prepareStatement(SAVE_KEY);
stmt.setString(1, keyId);
stmt.setString(2, json);
stmt.setString(3, json);
stmt.execute();
} catch (SQLException e) {
throw new RuntimeException(e);
}
return this;
}
}

1
settings.gradle

@ -7,4 +7,5 @@ include 'de.srsoftware.oidc.backend' @@ -7,4 +7,5 @@ include 'de.srsoftware.oidc.backend'
include 'de.srsoftware.oidc.datastore.file'
include 'de.srsoftware.oidc.web'
include 'de.srsoftware.utils'
include 'de.srsoftware.oidc.datastore.sqlite'

Loading…
Cancel
Save