working on SqliteUserService
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -25,7 +25,7 @@ public interface UserService {
|
|||||||
public Optional<User> forToken(String accessToken);
|
public Optional<User> forToken(String accessToken);
|
||||||
public UserService init(User defaultUser);
|
public UserService init(User defaultUser);
|
||||||
public List<User> list();
|
public List<User> list();
|
||||||
public Set<User> find(String key);
|
public Set<User> find(String idOrEmail);
|
||||||
public Optional<User> load(String id);
|
public Optional<User> load(String id);
|
||||||
public Optional<User> load(String username, String password);
|
public Optional<User> load(String username, String password);
|
||||||
public boolean passwordMatches(String password, String hashedPassword);
|
public boolean passwordMatches(String password, String hashedPassword);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class Application {
|
|||||||
|
|
||||||
|
|
||||||
FileStoreProvider fileStoreProvider = new FileStoreProvider(passHasher);
|
FileStoreProvider fileStoreProvider = new FileStoreProvider(passHasher);
|
||||||
var userService = setupUserService(config, defaultFile, fileStoreProvider).init(firstUser);
|
var userService = setupUserService(config, defaultFile, fileStoreProvider, passHasher).init(firstUser);
|
||||||
var sessionService = setupSessionService(config, defaultFile, fileStoreProvider);
|
var sessionService = setupSessionService(config, defaultFile, fileStoreProvider);
|
||||||
var mailConfig = setupMailConfig(config, defaultFile, fileStoreProvider);
|
var mailConfig = setupMailConfig(config, defaultFile, fileStoreProvider);
|
||||||
var keyStore = setupKeyStore(config, configDir);
|
var keyStore = setupKeyStore(config, configDir);
|
||||||
@@ -116,10 +116,10 @@ public class Application {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UserService setupUserService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
|
private static UserService setupUserService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider, UuidHasher passHasher) throws SQLException {
|
||||||
var userStorageLocation = new File(config.getOrDefault("user_storage",defaultFile));
|
var userStorageLocation = new File(config.getOrDefault("user_storage",defaultFile));
|
||||||
return switch (extension(userStorageLocation).toLowerCase()){
|
return switch (extension(userStorageLocation).toLowerCase()){
|
||||||
case "db", "sqlite", "sqlite3" -> new SqliteUserService(connectionProvider.get(userStorageLocation));
|
case "db", "sqlite", "sqlite3" -> new SqliteUserService(connectionProvider.get(userStorageLocation),passHasher);
|
||||||
default -> fileStoreProvider.get(userStorageLocation);
|
default -> fileStoreProvider.get(userStorageLocation);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
|
|||||||
var result = new HashSet<User>();
|
var result = new HashSet<User>();
|
||||||
for (var id : users.keySet()) {
|
for (var id : users.keySet()) {
|
||||||
var data = users.getJSONObject(id);
|
var data = users.getJSONObject(id);
|
||||||
if (id.equals(key)) User.of(data, id).ifPresent(result::add);
|
|
||||||
if (KEYS.stream().map(data::getString).anyMatch(val -> val.equals(key))) User.of(data, id).ifPresent(result::add);
|
if (KEYS.stream().map(data::getString).anyMatch(val -> val.equals(key))) User.of(data, id).ifPresent(result::add);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -181,13 +180,12 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
|
|||||||
public Optional<User> load(String user, String password) {
|
public Optional<User> load(String user, String password) {
|
||||||
try {
|
try {
|
||||||
var users = json.getJSONObject(USERS);
|
var users = json.getJSONObject(USERS);
|
||||||
var uuids = users.keySet();
|
for (String userId : users.keySet()) {
|
||||||
for (String userId : uuids) {
|
|
||||||
var userData = users.getJSONObject(userId);
|
var userData = users.getJSONObject(userId);
|
||||||
|
|
||||||
if (KEYS.stream().map(userData::getString).noneMatch(val -> val.equals(user))) continue;
|
if (KEYS.stream().map(userData::getString).noneMatch(val -> val.equals(user))) continue;
|
||||||
var hashedPass = userData.getString(PASSWORD);
|
var hashedPass = userData.getString(PASSWORD);
|
||||||
if (passwordHasher.matches(password, hashedPass)) return User.of(userData, userId);
|
if (passwordMatches(password, hashedPass)) return User.of(userData, userId);
|
||||||
}
|
}
|
||||||
return empty();
|
return empty();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
/* © SRSoftware 2024 */
|
/* © SRSoftware 2024 */
|
||||||
package de.srsoftware.oidc.datastore.sqlite;
|
package de.srsoftware.oidc.datastore.sqlite;
|
||||||
|
|
||||||
|
import static de.srsoftware.utils.Optionals.nullable;
|
||||||
import static de.srsoftware.utils.Strings.uuid;
|
import static de.srsoftware.utils.Strings.uuid;
|
||||||
import static java.util.Optional.empty;
|
import static java.util.Optional.empty;
|
||||||
|
|
||||||
|
import de.srsoftware.oidc.api.PasswordHasher;
|
||||||
import de.srsoftware.oidc.api.UserService;
|
import de.srsoftware.oidc.api.UserService;
|
||||||
import de.srsoftware.oidc.api.data.AccessToken;
|
import de.srsoftware.oidc.api.data.AccessToken;
|
||||||
import de.srsoftware.oidc.api.data.Permission;
|
import de.srsoftware.oidc.api.data.Permission;
|
||||||
@@ -17,23 +19,29 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class SqliteUserService extends SqliteStore implements UserService {
|
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 CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS users(uuid VARCHAR(255) NOT NULL PRIMARY KEY, password VARCHAR(255), email VARCHAR(255), session_duration INT NOT NULL DEFAULT 10, username VARCHAR(255), realname VARCHAR(255));";
|
||||||
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 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 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 LOAD_USER = "SELECT * FROM users WHERE uuid = ?";
|
||||||
private static final String DROP_PERMISSIONS = "DELETE FROM user_permissions WHERE uuid = ?";
|
private static final String FIND_USER = "SELECT * FROM users WHERE uuid = ? OR username LIKE ? OR realname LIKE ? ORDER BY COALESCE(uuid, ?), username";
|
||||||
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_USERS = "SELECT * FROM users";
|
||||||
private static final String LIST_USER_PERMISSIONS = "SELECT * FROM user_permissions WHERE uuid = ?";
|
private static final String LIST_USER_PERMISSIONS = "SELECT * FROM user_permissions WHERE uuid = ?";
|
||||||
|
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 INSERT_USER = "INSERT INTO users (uuid,password,email,session_duration,username,realname) VALUES (?,?,?,?,?,?)";
|
||||||
|
private static final String INSERT_PERMISSIONS = "INSERT INTO user_permissions (uuid, permission) VALUES (?,?)";
|
||||||
|
|
||||||
|
private static final String DROP_PERMISSIONS = "DELETE FROM user_permissions WHERE uuid = ?";
|
||||||
|
private static final String DROP_USER = "DELETE FROM users WHERE uuid = ?";
|
||||||
|
private static final String UPDATE_PASSWORD = "UPDATE users SET password = ? WHERE uuid = ?";
|
||||||
|
private final PasswordHasher<String> hasher;
|
||||||
|
|
||||||
private Map<String, AccessToken> accessTokens = new HashMap<>();
|
private Map<String, AccessToken> accessTokens = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
public SqliteUserService(Connection connection) throws SQLException {
|
public SqliteUserService(Connection connection, PasswordHasher<String> passHasher) throws SQLException {
|
||||||
super(connection);
|
super(connection);
|
||||||
|
hasher = passHasher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -50,10 +58,9 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dropPermissionsOf(String uuid) throws SQLException {
|
private void createUserStoreTables() throws SQLException {
|
||||||
var stmt = conn.prepareStatement(DROP_PERMISSIONS);
|
conn.prepareStatement(CREATE_USER_TABLE).execute();
|
||||||
stmt.setString(1, uuid);
|
conn.prepareStatement(CREATE_USER_PERMISSION_TABLE).execute();
|
||||||
stmt.execute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,6 +78,12 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dropPermissionsOf(String uuid) throws SQLException {
|
||||||
|
var stmt = conn.prepareStatement(DROP_PERMISSIONS);
|
||||||
|
stmt.setString(1, uuid);
|
||||||
|
stmt.execute();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<User> forToken(String id) {
|
public Optional<User> forToken(String id) {
|
||||||
AccessToken token = accessTokens.get(id);
|
AccessToken token = accessTokens.get(id);
|
||||||
@@ -85,29 +98,8 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
try {
|
try {
|
||||||
var rs = conn.prepareStatement(COUNT_USERS).executeQuery();
|
var rs = conn.prepareStatement(COUNT_USERS).executeQuery();
|
||||||
var count = rs.next() ? rs.getInt(1) : 0;
|
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();
|
rs.close();
|
||||||
conn.setAutoCommit(false);
|
if (count < 1) save(defaultUser);
|
||||||
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) {
|
} catch (SQLException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -143,10 +135,6 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
conn.setAutoCommit(true);
|
conn.setAutoCommit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createUserStoreTables() throws SQLException {
|
|
||||||
conn.prepareStatement(CREATE_USER_TABLE).execute();
|
|
||||||
conn.prepareStatement(CREATE_USER_PERMISSION_TABLE).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<User> list() {
|
public List<User> list() {
|
||||||
@@ -181,37 +169,97 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
var user = rs.getString("username");
|
var user = rs.getString("username");
|
||||||
var name = rs.getString("realname");
|
var name = rs.getString("realname");
|
||||||
var mail = rs.getString("email");
|
var mail = rs.getString("email");
|
||||||
var mins = rs.getLong("sessionDuration");
|
var mins = rs.getLong("session_duration");
|
||||||
return new User(user, pass, name, mail, uuid).sessionDuration(Duration.ofMinutes(mins));
|
return new User(user, pass, name, mail, uuid).sessionDuration(Duration.ofMinutes(mins));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<User> find(String key) {
|
public Set<User> find(String idOrEmail) {
|
||||||
return Set.of();
|
try {
|
||||||
|
var result = new HashSet<User>();
|
||||||
|
var stmt = conn.prepareStatement(FIND_USER); // TODO: implement test for this query
|
||||||
|
stmt.setString(1, idOrEmail);
|
||||||
|
stmt.setString(2, "%" + idOrEmail + "%");
|
||||||
|
stmt.setString(3, "%" + idOrEmail + "%");
|
||||||
|
stmt.setString(4, idOrEmail);
|
||||||
|
var rs = stmt.executeQuery();
|
||||||
|
while (rs.next()) result.add(userFrom(rs));
|
||||||
|
rs.close();
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<User> load(String id) {
|
public Optional<User> load(String id) {
|
||||||
return Optional.empty();
|
try {
|
||||||
|
User user = null;
|
||||||
|
var stmt = conn.prepareStatement(LOAD_USER);
|
||||||
|
stmt.setString(1, id);
|
||||||
|
var rs = stmt.executeQuery();
|
||||||
|
if (rs.next()) user = userFrom(rs);
|
||||||
|
return nullable(user);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<User> load(String username, String password) {
|
public Optional<User> load(String username, String password) {
|
||||||
return Optional.empty();
|
var candidates = find(username);
|
||||||
|
for (var user : candidates) {
|
||||||
|
if (passwordMatches(password, user.hashedPassword())) return Optional.of(user);
|
||||||
|
}
|
||||||
|
return empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean passwordMatches(String password, String hashedPassword) {
|
public boolean passwordMatches(String password, String hashedPassword) {
|
||||||
return false;
|
return hasher.matches(password, hashedPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends UserService> T save(User user) {
|
public SqliteUserService save(User user) {
|
||||||
return null;
|
try {
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
var stmt = conn.prepareStatement(INSERT_USER);
|
||||||
|
stmt.setString(1, user.uuid());
|
||||||
|
stmt.setString(2, user.hashedPassword());
|
||||||
|
stmt.setString(3, user.email());
|
||||||
|
stmt.setLong(4, user.sessionDuration().toMinutes());
|
||||||
|
stmt.setString(5, user.username());
|
||||||
|
stmt.setString(6, user.realName());
|
||||||
|
stmt.execute();
|
||||||
|
dropPermissionsOf(user.uuid());
|
||||||
|
|
||||||
|
stmt = conn.prepareStatement(INSERT_PERMISSIONS);
|
||||||
|
stmt.setString(1, user.uuid());
|
||||||
|
for (Permission perm : Permission.values()) {
|
||||||
|
if (user.hasPermission(perm)) {
|
||||||
|
stmt.setString(2, perm.toString());
|
||||||
|
stmt.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.commit();
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends UserService> T updatePassword(User user, String plaintextPassword) {
|
public SqliteUserService updatePassword(User user, String plaintextPassword) {
|
||||||
return null;
|
try {
|
||||||
|
var stmt = conn.prepareStatement(UPDATE_PASSWORD);
|
||||||
|
stmt.setString(1, user.uuid());
|
||||||
|
var hashedPassword = hasher.hash(plaintextPassword, uuid());
|
||||||
|
stmt.setString(2, hashedPassword);
|
||||||
|
stmt.execute();
|
||||||
|
return this;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user