implemented SqliteSessionService
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -80,7 +80,7 @@ public abstract class SessionServiceTest {
|
|||||||
|
|
||||||
sessionService().dropSession(session.id());
|
sessionService().dropSession(session.id());
|
||||||
var loaded = sessionService().retrieve(session.id());
|
var loaded = sessionService().retrieve(session.id());
|
||||||
assertTrue(sessionService().retrieve(session.id()).isEmpty());
|
assertTrue(loaded.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -16,13 +16,17 @@ import org.jose4j.jwk.PublicJsonWebKey;
|
|||||||
import org.jose4j.lang.JoseException;
|
import org.jose4j.lang.JoseException;
|
||||||
|
|
||||||
public class SqliteKeyStore extends SqliteStore implements KeyStorage {
|
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 STORE_VERSION = "key_store_version";
|
||||||
private static final String SET_KEYSTORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = 'key_store_version'";
|
private static final String CREATE_STORE_VERSION = "INSERT INTO metainfo (key,value) VALUES ('" + STORE_VERSION + "','0')";
|
||||||
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 SELECT_STORE_VERSION = "SELECT * FROM metainfo WHERE key = '" + STORE_VERSION + "'";
|
||||||
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 SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'";
|
||||||
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 SET_KEYSTORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = 'key_store_version'";
|
||||||
private static final String DROP_KEY = "DELETE FROM keystore WHERE key_id = ?";
|
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 = ?";
|
||||||
|
|
||||||
private HashMap<String, PublicJsonWebKey> loaded = new HashMap<>();
|
private HashMap<String, PublicJsonWebKey> loaded = new HashMap<>();
|
||||||
|
|
||||||
@@ -30,36 +34,7 @@ public class SqliteKeyStore extends SqliteStore implements KeyStorage {
|
|||||||
super(connection);
|
super(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void createStoreTables() throws SQLException {
|
||||||
protected void initTables() throws SQLException {
|
|
||||||
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();
|
conn.prepareStatement(CREATE_KEYSTORE_TABLE).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +50,41 @@ public class SqliteKeyStore extends SqliteStore implements KeyStorage {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initTables() throws SQLException {
|
||||||
|
var rs = conn.prepareStatement(SELECT_STORE_VERSION).executeQuery();
|
||||||
|
int availableVersion = 1;
|
||||||
|
int currentVersion;
|
||||||
|
if (rs.next()) {
|
||||||
|
currentVersion = rs.getInt(1);
|
||||||
|
rs.close();
|
||||||
|
} else {
|
||||||
|
rs.close();
|
||||||
|
conn.prepareStatement(CREATE_STORE_VERSION).execute();
|
||||||
|
currentVersion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
var stmt = conn.prepareStatement(SET_STORE_VERSION);
|
||||||
|
while (currentVersion < availableVersion) {
|
||||||
|
try {
|
||||||
|
switch (currentVersion) {
|
||||||
|
case 0:
|
||||||
|
createStoreTables();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stmt.setInt(1, ++currentVersion);
|
||||||
|
stmt.execute();
|
||||||
|
conn.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
conn.rollback();
|
||||||
|
LOG.log(System.Logger.Level.ERROR, "Failed to update at {} = {}", STORE_VERSION, currentVersion);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.setAutoCommit(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listKeys() {
|
public List<String> listKeys() {
|
||||||
var result = new ArrayList<String>();
|
var result = new ArrayList<String>();
|
||||||
|
|||||||
@@ -19,11 +19,43 @@ public class SqliteSessionService extends SqliteStore implements SessionService
|
|||||||
private static final String SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'";
|
private static final String SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'";
|
||||||
|
|
||||||
private static final String CREATE_SESSION_TABLE = "CREATE TABLE sessions (id VARCHAR(64) PRIMARY KEY, userId VARCHAR(64) NOT NULL, expiration LONG NOT NULL)";
|
private static final String CREATE_SESSION_TABLE = "CREATE TABLE sessions (id VARCHAR(64) PRIMARY KEY, userId VARCHAR(64) NOT NULL, expiration LONG NOT NULL)";
|
||||||
|
private static final String SAVE_SESSION = "INSERT INTO sessions (id, userId, expiration) VALUES (?,?,?) ON CONFLICT DO UPDATE SET expiration = ?;";
|
||||||
|
private static final String DROP_SESSION = "DELETE FROM sessions WHERE id = ?";
|
||||||
|
private static final String SELECT_SESSION = "SELECT * FROM sessions WHERE id = ?";
|
||||||
|
|
||||||
public SqliteSessionService(Connection connection) throws SQLException {
|
public SqliteSessionService(Connection connection) throws SQLException {
|
||||||
super(connection);
|
super(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Session createSession(User user) {
|
||||||
|
var now = Instant.now();
|
||||||
|
var endOfSession = now.plus(user.sessionDuration()).truncatedTo(SECONDS);
|
||||||
|
return save(new Session(user.uuid(), endOfSession, uuid()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createStoreTables() throws SQLException {
|
||||||
|
conn.prepareStatement(CREATE_SESSION_TABLE).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SessionService dropSession(String sessionId) {
|
||||||
|
try {
|
||||||
|
var stmt = conn.prepareStatement(DROP_SESSION);
|
||||||
|
stmt.setString(1, sessionId);
|
||||||
|
stmt.execute();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Session extend(Session session, User user) {
|
||||||
|
var endOfSession = Instant.now().plus(user.sessionDuration());
|
||||||
|
return save(new Session(user.uuid(), endOfSession, session.id()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initTables() throws SQLException {
|
protected void initTables() throws SQLException {
|
||||||
var rs = conn.prepareStatement(SELECT_STORE_VERSION).executeQuery();
|
var rs = conn.prepareStatement(SELECT_STORE_VERSION).executeQuery();
|
||||||
@@ -59,33 +91,37 @@ public class SqliteSessionService extends SqliteStore implements SessionService
|
|||||||
conn.setAutoCommit(true);
|
conn.setAutoCommit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createStoreTables() throws SQLException {
|
|
||||||
conn.prepareStatement(CREATE_SESSION_TABLE).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Session createSession(User user) {
|
|
||||||
var now = Instant.now();
|
|
||||||
var endOfSession = now.plus(user.sessionDuration()).truncatedTo(SECONDS);
|
|
||||||
return save(new Session(user.uuid(), endOfSession, uuid()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SessionService dropSession(String sessionId) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Session extend(Session session, User user) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Session> retrieve(String sessionId) {
|
public Optional<Session> retrieve(String sessionId) {
|
||||||
return Optional.empty();
|
try {
|
||||||
|
var stmt = conn.prepareStatement(SELECT_SESSION);
|
||||||
|
stmt.setString(1, sessionId);
|
||||||
|
var rs = stmt.executeQuery();
|
||||||
|
Optional<Session> result = Optional.empty();
|
||||||
|
if (rs.next()) {
|
||||||
|
var userID = rs.getString("userId");
|
||||||
|
var expiration = Instant.ofEpochSecond(rs.getLong("expiration"));
|
||||||
|
if (expiration.isAfter(Instant.now())) result = Optional.of(new Session(userID, expiration, sessionId));
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
return result;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Session save(Session session) {
|
private Session save(Session session) {
|
||||||
return session;
|
try {
|
||||||
|
var stmt = conn.prepareStatement(SAVE_SESSION);
|
||||||
|
var expiration = session.expiration().getEpochSecond();
|
||||||
|
stmt.setString(1, session.id());
|
||||||
|
stmt.setString(2, session.userId());
|
||||||
|
stmt.setLong(3, expiration);
|
||||||
|
stmt.setLong(4, expiration);
|
||||||
|
stmt.execute();
|
||||||
|
return session;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
private static final String LOAD_PERMISSIONS = "SELECT permission FROM user_permissions WHERE uuid = ?";
|
private static final String LOAD_PERMISSIONS = "SELECT permission FROM user_permissions WHERE uuid = ?";
|
||||||
private static final String FIND_USER = "SELECT * FROM users WHERE uuid = ? OR username LIKE ? OR realname LIKE ? OR email = ? ORDER BY COALESCE(uuid, ?), username";
|
private static final String FIND_USER = "SELECT * FROM users WHERE uuid = ? OR username LIKE ? OR realname LIKE ? OR email = ? ORDER BY COALESCE(uuid, ?), username";
|
||||||
private static final String LIST_USERS = "SELECT * FROM users";
|
private static final String LIST_USERS = "SELECT * FROM users";
|
||||||
private static final String INSERT_USER = "INSERT INTO users (uuid,password,email,session_duration,username,realname) VALUES (?,?,?,?,?,?) ON CONFLICT DO UPDATE SET password = ?, email = ?, session_duration = ?, username = ?, realname = ?;";
|
private static final String SAVE_USER = "INSERT INTO users (uuid,password,email,session_duration,username,realname) VALUES (?,?,?,?,?,?) ON CONFLICT DO UPDATE SET password = ?, email = ?, session_duration = ?, username = ?, realname = ?;";
|
||||||
private static final String INSERT_PERMISSIONS = "INSERT INTO user_permissions (uuid, permission) 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_PERMISSIONS = "DELETE FROM user_permissions WHERE uuid = ?";
|
||||||
private static final String DROP_USER = "DELETE FROM users WHERE uuid = ?";
|
private static final String DROP_USER = "DELETE FROM users WHERE uuid = ?";
|
||||||
@@ -53,6 +53,22 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private User addPermissions(User user) {
|
||||||
|
try {
|
||||||
|
var stmt = conn.prepareStatement(LOAD_PERMISSIONS);
|
||||||
|
stmt.setString(1, user.uuid());
|
||||||
|
var rs = stmt.executeQuery();
|
||||||
|
while (rs.next()) try {
|
||||||
|
user.add(Permission.valueOf(rs.getString("permission")));
|
||||||
|
} catch (IllegalArgumentException ignored) {
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
return user;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<User> consumeToken(String id) {
|
public Optional<User> consumeToken(String id) {
|
||||||
var user = forToken(id);
|
var user = forToken(id);
|
||||||
@@ -86,6 +102,25 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
stmt.execute();
|
stmt.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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);
|
||||||
|
stmt.setString(5, 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> forToken(String id) {
|
public Optional<User> forToken(String id) {
|
||||||
AccessToken token = accessTokens.get(id);
|
AccessToken token = accessTokens.get(id);
|
||||||
@@ -158,35 +193,6 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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("session_duration");
|
|
||||||
return new User(user, pass, name, mail, uuid).sessionDuration(Duration.ofMinutes(mins));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
stmt.setString(5, 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) {
|
||||||
try {
|
try {
|
||||||
@@ -202,22 +208,6 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private User addPermissions(User user) {
|
|
||||||
try {
|
|
||||||
var stmt = conn.prepareStatement(LOAD_PERMISSIONS);
|
|
||||||
stmt.setString(1, user.uuid());
|
|
||||||
var rs = stmt.executeQuery();
|
|
||||||
while (rs.next()) try {
|
|
||||||
user.add(Permission.valueOf(rs.getString("permission")));
|
|
||||||
} catch (IllegalArgumentException ignored) {
|
|
||||||
}
|
|
||||||
rs.close();
|
|
||||||
return 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) {
|
||||||
var candidates = find(username);
|
var candidates = find(username);
|
||||||
@@ -236,7 +226,7 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
public SqliteUserService save(User user) {
|
public SqliteUserService save(User user) {
|
||||||
try {
|
try {
|
||||||
conn.setAutoCommit(false);
|
conn.setAutoCommit(false);
|
||||||
var stmt = conn.prepareStatement(INSERT_USER);
|
var stmt = conn.prepareStatement(SAVE_USER);
|
||||||
stmt.setString(1, user.uuid());
|
stmt.setString(1, user.uuid());
|
||||||
stmt.setString(2, user.hashedPassword());
|
stmt.setString(2, user.hashedPassword());
|
||||||
stmt.setString(3, user.email());
|
stmt.setString(3, user.email());
|
||||||
@@ -270,4 +260,14 @@ public class SqliteUserService extends SqliteStore implements UserService {
|
|||||||
public SqliteUserService updatePassword(User user, String plaintextPassword) {
|
public SqliteUserService updatePassword(User user, String plaintextPassword) {
|
||||||
return save(user.hashedPassword(hasher.hash(plaintextPassword, uuid())));
|
return save(user.hashedPassword(hasher.hash(plaintextPassword, uuid())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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("session_duration");
|
||||||
|
return new User(user, pass, name, mail, uuid).sessionDuration(Duration.ofMinutes(mins));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user