Browse Source

implemented SqliteSessionService

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 2 months ago
parent
commit
79431ca680
  1. 2
      de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/SessionServiceTest.java
  2. 66
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteKeyStore.java
  3. 78
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteSessionService.java
  4. 94
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteUserService.java

2
de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/SessionServiceTest.java

@ -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

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

@ -16,7 +16,11 @@ 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 CREATE_STORE_VERSION = "INSERT INTO metainfo (key,value) VALUES ('" + STORE_VERSION + "','0')";
private static final String SELECT_STORE_VERSION = "SELECT * FROM metainfo WHERE key = '" + STORE_VERSION + "'";
private static final String SET_STORE_VERSION = "UPDATE metainfo SET value = ? WHERE key = '" + STORE_VERSION + "'";
private static final String SET_KEYSTORE_VERSION = "UPDATE metainfo SET value = ? 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);"; 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 SAVE_KEY = "INSERT INTO keystore(key_id, json) values (?,?) ON CONFLICT(key_id) DO UPDATE SET json = ?";
@ -30,51 +34,57 @@ public class SqliteKeyStore extends SqliteStore implements KeyStorage {
super(connection); super(connection);
} }
private void createStoreTables() throws SQLException {
conn.prepareStatement(CREATE_KEYSTORE_TABLE).execute();
}
@Override
public KeyStorage drop(String keyId) {
try {
var stmt = conn.prepareStatement(DROP_KEY);
stmt.setString(1, keyId);
stmt.execute();
} catch (SQLException e) {
LOG.log(System.Logger.Level.WARNING, "Failed to drop key {0} from database:", keyId, e);
}
return this;
}
@Override @Override
protected void initTables() throws SQLException { protected void initTables() throws SQLException {
var rs = conn.prepareStatement(SELECT_KEYSTORE_VERSION).executeQuery(); var rs = conn.prepareStatement(SELECT_STORE_VERSION).executeQuery();
int availableVersion = 1; int availableVersion = 1;
int lastVersion = 1; int currentVersion;
if (rs.next()) { if (rs.next()) {
lastVersion = rs.getInt(1); currentVersion = rs.getInt(1);
} rs.close();
} else {
rs.close(); rs.close();
conn.prepareStatement(CREATE_STORE_VERSION).execute();
currentVersion = 0;
}
conn.setAutoCommit(false); conn.setAutoCommit(false);
var stmt = conn.prepareStatement(SET_KEYSTORE_VERSION); var stmt = conn.prepareStatement(SET_STORE_VERSION);
for (int version = lastVersion; version <= availableVersion; version++) { while (currentVersion < availableVersion) {
try { try {
switch (version) { switch (currentVersion) {
case 1: case 0:
createKeyStoreTables(); createStoreTables();
break;
} }
stmt.setInt(1, version); stmt.setInt(1, ++currentVersion);
stmt.execute(); stmt.execute();
conn.commit(); conn.commit();
} catch (Exception e) { } catch (Exception e) {
conn.rollback(); conn.rollback();
LOG.log(System.Logger.Level.ERROR, "Failed to update at keystore version = {0}", version); LOG.log(System.Logger.Level.ERROR, "Failed to update at {} = {}", STORE_VERSION, currentVersion);
break; break;
} }
} }
conn.setAutoCommit(true); conn.setAutoCommit(true);
} }
private void createKeyStoreTables() throws SQLException {
conn.prepareStatement(CREATE_KEYSTORE_TABLE).execute();
}
@Override
public KeyStorage drop(String keyId) {
try {
var stmt = conn.prepareStatement(DROP_KEY);
stmt.setString(1, keyId);
stmt.execute();
} catch (SQLException e) {
LOG.log(System.Logger.Level.WARNING, "Failed to drop key {0} from database:", keyId, e);
}
return this;
}
@Override @Override
public List<String> listKeys() { public List<String> listKeys() {
var result = new ArrayList<String>(); var result = new ArrayList<String>();

78
de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteSessionService.java

@ -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 @Override
public SessionService dropSession(String sessionId) { public Optional<Session> retrieve(String sessionId) {
return null; 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();
@Override return result;
public Session extend(Session session, User user) { } catch (SQLException e) {
return null; throw new RuntimeException(e);
} }
@Override
public Optional<Session> retrieve(String sessionId) {
return Optional.empty();
} }
private Session save(Session session) { private Session save(Session 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; return session;
} catch (SQLException e) {
throw new RuntimeException(e);
}
} }
} }

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

@ -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));
}
} }

Loading…
Cancel
Save