Browse Source

working on SqliteUserService

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 3 months ago
parent
commit
9124ff570e
  1. 2
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java
  2. 6
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  3. 6
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  4. 144
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteUserService.java

2
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java

@ -25,7 +25,7 @@ public interface UserService { @@ -25,7 +25,7 @@ public interface UserService {
public Optional<User> forToken(String accessToken);
public UserService init(User defaultUser);
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 username, String password);
public boolean passwordMatches(String password, String hashedPassword);

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

@ -63,7 +63,7 @@ public class Application { @@ -63,7 +63,7 @@ public class Application {
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 mailConfig = setupMailConfig(config, defaultFile, fileStoreProvider);
var keyStore = setupKeyStore(config, configDir);
@ -116,10 +116,10 @@ public class Application { @@ -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));
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);
};
}

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

@ -151,7 +151,6 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -151,7 +151,6 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
var result = new HashSet<User>();
for (var id : users.keySet()) {
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);
}
return result;
@ -181,13 +180,12 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -181,13 +180,12 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
public Optional<User> load(String user, String password) {
try {
var users = json.getJSONObject(USERS);
var uuids = users.keySet();
for (String userId : uuids) {
for (String userId : users.keySet()) {
var userData = users.getJSONObject(userId);
if (KEYS.stream().map(userData::getString).noneMatch(val -> val.equals(user))) continue;
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();
} catch (Exception e) {

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

@ -1,9 +1,11 @@ @@ -1,9 +1,11 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.utils.Optionals.nullable;
import static de.srsoftware.utils.Strings.uuid;
import static java.util.Optional.empty;
import de.srsoftware.oidc.api.PasswordHasher;
import de.srsoftware.oidc.api.UserService;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.Permission;
@ -17,23 +19,29 @@ import java.time.temporal.ChronoUnit; @@ -17,23 +19,29 @@ 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_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 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 LOAD_USER = "SELECT * FROM users 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 LIST_USERS = "SELECT * FROM users";
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<>();
public SqliteUserService(Connection connection) throws SQLException {
public SqliteUserService(Connection connection, PasswordHasher<String> passHasher) throws SQLException {
super(connection);
hasher = passHasher;
}
@Override
@ -50,10 +58,9 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -50,10 +58,9 @@ public class SqliteUserService extends SqliteStore implements UserService {
return user;
}
private void dropPermissionsOf(String uuid) throws SQLException {
var stmt = conn.prepareStatement(DROP_PERMISSIONS);
stmt.setString(1, uuid);
stmt.execute();
private void createUserStoreTables() throws SQLException {
conn.prepareStatement(CREATE_USER_TABLE).execute();
conn.prepareStatement(CREATE_USER_PERMISSION_TABLE).execute();
}
@Override
@ -71,6 +78,12 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -71,6 +78,12 @@ public class SqliteUserService extends SqliteStore implements UserService {
return this;
}
private void dropPermissionsOf(String uuid) throws SQLException {
var stmt = conn.prepareStatement(DROP_PERMISSIONS);
stmt.setString(1, uuid);
stmt.execute();
}
@Override
public Optional<User> forToken(String id) {
AccessToken token = accessTokens.get(id);
@ -85,29 +98,8 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -85,29 +98,8 @@ public class SqliteUserService extends SqliteStore implements UserService {
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();
if (count < 1) save(defaultUser);
} catch (SQLException e) {
throw new RuntimeException(e);
}
@ -143,10 +135,6 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -143,10 +135,6 @@ public class SqliteUserService extends SqliteStore implements UserService {
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() {
@ -181,37 +169,97 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -181,37 +169,97 @@ public class SqliteUserService extends SqliteStore implements UserService {
var user = rs.getString("username");
var name = rs.getString("realname");
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));
}
@Override
public Set<User> find(String key) {
return Set.of();
public Set<User> find(String idOrEmail) {
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
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
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
public boolean passwordMatches(String password, String hashedPassword) {
return false;
return hasher.matches(password, hashedPassword);
}
@Override
public <T extends UserService> T save(User user) {
return null;
public SqliteUserService save(User user) {
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
public <T extends UserService> T updatePassword(User user, String plaintextPassword) {
return null;
public SqliteUserService updatePassword(User user, String plaintextPassword) {
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);
}
}
}

Loading…
Cancel
Save