started to implement SqliteUserService
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 implements UserService {
|
||||
private final Connection conn;
|
||||
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 = ?";
|
||||
|
||||
public SqliteUserService(Connection connection) {
|
||||
conn = connection;
|
||||
private Map<String, AccessToken> accessTokens = new HashMap<>();
|
||||
|
||||
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user