Browse Source

started to implement SqliteUserService

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 3 months ago
parent
commit
47910b5460
  1. 3
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/User.java
  2. 2
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  3. 1
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  4. 12
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteKeyStore.java
  5. 20
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteStore.java
  6. 168
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteUserService.java

3
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/data/User.java

@ -128,8 +128,9 @@ public final class User { @@ -128,8 +128,9 @@ public final class User {
return uuid;
}
public void sessionDuration(Duration newVal) {
public User sessionDuration(Duration newVal) {
sessionDuration = newVal;
return this;
}
public Duration sessionDuration() {

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

@ -116,7 +116,7 @@ public class Application { @@ -116,7 +116,7 @@ public class Application {
};
}
private static UserService setupUserService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) {
private static UserService setupUserService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
var userStorageLocation = new File(config.getOrDefault("user_storage",defaultFile));
return switch (extension(userStorageLocation).toLowerCase()){
case "db", "sqlite", "sqlite3" -> new SqliteUserService(connectionProvider.get(userStorageLocation));

1
de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java

@ -27,7 +27,6 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -27,7 +27,6 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
private static final System.Logger LOG = System.getLogger(FileStore.class.getSimpleName());
private static final String AUTHORIZATIONS = "authorizations";
private static final String CLIENTS = "clients";
private static final String CODES = "codes";
private static final String REDIRECT_URIS = "redirect_uris";
private static final String SESSIONS = "sessions";
private static final String USERS = "users";

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

@ -15,8 +15,7 @@ import java.util.List; @@ -15,8 +15,7 @@ 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);";
public class SqliteKeyStore extends SqliteStore implements KeyStorage {
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);";
@ -24,18 +23,15 @@ public class SqliteKeyStore implements KeyStorage { @@ -24,18 +23,15 @@ public class SqliteKeyStore implements KeyStorage {
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();
super(connection);
}
private void initTables() throws SQLException {
conn.prepareStatement(CREATE_MIGRATION_TABLE).execute();
@Override
protected void initTables() throws SQLException {
var rs = conn.prepareStatement(SELECT_KEYSTORE_VERSION).executeQuery();
int availableVersion = 1;
int lastVersion = 1;

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

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite;
import java.sql.Connection;
import java.sql.SQLException;
public abstract class SqliteStore {
public static System.Logger LOG = System.getLogger(SqliteStore.class.getSimpleName());
private static final String CREATE_MIGRATION_TABLE = "CREATE TABLE IF NOT EXISTS metainfo(key VARCHAR(255) PRIMARY KEY, value TEXT);";
protected final Connection conn;
public SqliteStore(Connection connection) throws SQLException {
conn = connection;
conn.prepareStatement(CREATE_MIGRATION_TABLE).execute();
initTables();
}
protected abstract void initTables() throws SQLException;
}

168
de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteUserService.java

@ -1,50 +1,190 @@ @@ -1,50 +1,190 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.utils.Strings.uuid;
import static java.util.Optional.empty;
import de.srsoftware.oidc.api.UserService;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.Permission;
import de.srsoftware.oidc.api.data.User;
import java.sql.Connection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
public class SqliteUserService extends SqliteStore implements UserService {
private static final String SELECT_USERSTORE_VERSION = "SELECT * FROM metainfo WHERE key = 'user_store_version'";
private static final String SET_USERSTORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = 'user_store_version'";
private static final String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS users(uuid VARCHAR(255) NOT NULL PRIMARY KEY, password VARCHAR(255), email VARCHAR(255), sessionDuration INT NOT NULL DEFAULT 10, username VARCHAR(255), realname VARCHAR(255));";
private static final String CREATE_USER_PERMISSION_TABLE = "CREATE TABLE IF NOT EXISTS user_permissions(uuid VARCHAR(255), permission VARCHAR(50), PRIMARY KEY(uuid,permission));";
private static final String COUNT_USERS = "SELECT count(*) FROM users";
private static final String INSERT_USER = "INSERT INTO users (uuid,password,email,sessionDuration,username,realname) VALUES (?,?,?,?,?,?)";
private static final String DROP_PERMISSIONS = "DELETE FROM user_permissions WHERE uuid = ?";
private static final String INSERT_PERMISSIONS = "INSERT INTO user_permissions (uuid, permission) VALUES (?,?)";
private static final String DROP_USER = "DELETE FROM users WHERE uuid = ?";
private static final String LIST_USERS = "SELECT * FROM users";
private static final String LIST_USER_PERMISSIONS = "SELECT * FROM user_permissions WHERE uuid = ?";
private Map<String, AccessToken> accessTokens = new HashMap<>();
public class SqliteUserService implements UserService {
private final Connection conn;
public SqliteUserService(Connection connection) {
conn = connection;
public SqliteUserService(Connection connection) throws SQLException {
super(connection);
}
@Override
public AccessToken accessToken(User user) {
return null;
var token = new AccessToken(uuid(), Objects.requireNonNull(user), Instant.now().plus(1, ChronoUnit.HOURS));
accessTokens.put(token.id(), token);
return token;
}
@Override
public Optional<User> consumeToken(String accessToken) {
return Optional.empty();
public Optional<User> consumeToken(String id) {
var user = forToken(id);
accessTokens.remove(id);
return user;
}
private void dropPermissionsOf(String uuid) throws SQLException {
var stmt = conn.prepareStatement(DROP_PERMISSIONS);
stmt.setString(1, uuid);
stmt.execute();
}
@Override
public UserService delete(User user) {
return null;
try {
conn.setAutoCommit(false);
dropPermissionsOf(user.uuid());
var stmt = conn.prepareStatement(DROP_USER);
stmt.setString(1, user.uuid());
stmt.execute();
conn.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
return this;
}
@Override
public Optional<User> forToken(String accessToken) {
return Optional.empty();
public Optional<User> forToken(String id) {
AccessToken token = accessTokens.get(id);
if (token == null) return empty();
if (token.valid()) return Optional.of(token.user());
accessTokens.remove(id);
return empty();
}
@Override
public UserService init(User defaultUser) {
return null;
try {
var rs = conn.prepareStatement(COUNT_USERS).executeQuery();
var count = rs.next() ? rs.getInt(1) : 0;
if (count < 1) {
var stmt = conn.prepareStatement(INSERT_USER);
stmt.setString(1, defaultUser.uuid());
stmt.setString(2, defaultUser.hashedPassword());
stmt.setString(3, defaultUser.email());
stmt.setLong(4, defaultUser.sessionDuration().toMinutes());
stmt.setString(5, defaultUser.username());
stmt.setString(6, defaultUser.realName());
stmt.execute();
}
rs.close();
conn.setAutoCommit(false);
dropPermissionsOf(defaultUser.uuid());
var stmt = conn.prepareStatement(INSERT_PERMISSIONS);
stmt.setString(1, defaultUser.uuid());
for (Permission perm : Permission.values()) {
if (defaultUser.hasPermission(perm)) {
stmt.setString(2, perm.toString());
stmt.execute();
}
}
conn.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
return this;
}
@Override
protected void initTables() throws SQLException {
var rs = conn.prepareStatement(SELECT_USERSTORE_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_USERSTORE_VERSION);
for (int version = lastVersion; version <= availableVersion; version++) {
try {
switch (version) {
case 1:
createUserStoreTables();
}
stmt.setInt(1, version);
stmt.execute();
conn.commit();
} catch (Exception e) {
conn.rollback();
LOG.log(System.Logger.Level.ERROR, "Failed to update at user store version = {0}", version);
break;
}
}
conn.setAutoCommit(true);
}
private void createUserStoreTables() throws SQLException {
conn.prepareStatement(CREATE_USER_TABLE).execute();
conn.prepareStatement(CREATE_USER_PERMISSION_TABLE).execute();
}
@Override
public List<User> list() {
try {
List<User> result = new ArrayList<>();
var rs = conn.prepareStatement(LIST_USERS).executeQuery();
while (rs.next()) result.add(userFrom(rs));
rs.close();
for (User user : result) listPermissions(user.uuid()).forEach(user::add);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return List.of();
}
private List<Permission> listPermissions(String uuid) throws SQLException {
var perms = new ArrayList<Permission>();
var stmt = conn.prepareStatement(LIST_USER_PERMISSIONS);
stmt.setString(1, uuid);
var rs = stmt.executeQuery();
while (rs.next()) {
var perm = rs.getString("permission");
perms.add(Permission.valueOf(perm));
}
rs.close();
return perms;
}
private User userFrom(ResultSet rs) throws SQLException {
var uuid = rs.getString("uuid");
var pass = rs.getString("password");
var user = rs.getString("username");
var name = rs.getString("realname");
var mail = rs.getString("email");
var mins = rs.getLong("sessionDuration");
return new User(user, pass, name, mail, uuid).sessionDuration(Duration.ofMinutes(mins));
}
@Override
public Set<User> find(String key) {
return Set.of();

Loading…
Cancel
Save