Browse Source

implemented SqliteAuthService

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 2 months ago
parent
commit
cd3a5b39e3
  1. 4
      de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/AuthServiceTest.java
  2. 2
      de.srsoftware.oidc.app/src/main/java/de/srsoftware/oidc/app/Application.java
  3. 122
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteAuthService.java
  4. 26
      de.srsoftware.oidc.datastore.sqlite/src/test/java/de/srsoftware/oidc/datastore/sqlite/SqliteAuthServiceTest.java

4
de.srsoftware.oidc.api/src/test/java/de/srsoftware/oidc/api/AuthServiceTest.java

@ -25,8 +25,10 @@ public abstract class AuthServiceTest { @@ -25,8 +25,10 @@ public abstract class AuthServiceTest {
public void testAuthorize() {
var authorizationService = authorizationService();
var userId1 = uuid();
var expiration = Instant.now().plusSeconds(3600).truncatedTo(SECONDS);
var expiration = Instant.now();
authorizationService.authorize(userId1, CLIENT1, SCOPES1, expiration);
expiration = Instant.now().plusSeconds(3600).truncatedTo(SECONDS); // test overwrite
authorizationService.authorize(userId1, CLIENT1, SCOPES1, expiration); // test overwrite
var authorization = authorizationService.getAuthorization(userId1, CLIENT1, Set.of(OPENID));
assertEquals(1, authorization.authorizedScopes().scopes().size());
assertTrue(authorization.authorizedScopes().scopes().contains(OPENID));

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

@ -92,7 +92,7 @@ public class Application { @@ -92,7 +92,7 @@ public class Application {
};
}
private static AuthorizationService setupAuthService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) {
private static AuthorizationService setupAuthService(Configuration config, Path defaultFile, FileStoreProvider fileStoreProvider) throws SQLException {
var authServiceLocation = new File(config.getOrDefault("auth_store",defaultFile));
return switch (extension(authServiceLocation)){
case "db", "sqlite", "sqlite3" -> new SqliteAuthService(connectionProvider.get(authServiceLocation));

122
de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteAuthService.java

@ -1,30 +1,138 @@ @@ -1,30 +1,138 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.utils.Optionals.nullable;
import static de.srsoftware.utils.Strings.uuid;
import de.srsoftware.oidc.api.AuthorizationService;
import de.srsoftware.oidc.api.data.AuthResult;
import de.srsoftware.oidc.api.data.Authorization;
import de.srsoftware.oidc.api.data.AuthorizedScopes;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
public class SqliteAuthService extends SqliteStore implements AuthorizationService {
private static final String STORE_VERSION = "auth_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 CREATE_AUTHSTORE_TABLE = "CREATE TABLE IF NOT EXISTS authorizations(userId VARCHAR(255), clientId VARCHAR(255), scope VARCHAR(255), expiration LONG, PRIMARY KEY(userId, clientId, scope));";
private static final String SAVE_AUTHORIZATION = "INSERT INTO authorizations(userId, clientId, scope, expiration) VALUES (?,?,?,?) ON CONFLICT DO UPDATE SET expiration = ?";
private static final String SELECT_AUTH = "SELECT * FROM authorizations WHERE userid = ? AND clientId = ? AND scope IN";
private Map<String, Authorization> authCodes = new HashMap<>();
public SqliteAuthService(Connection connection) throws SQLException {
super(connection);
}
private void createStoreTables() throws SQLException {
conn.prepareStatement(CREATE_AUTHSTORE_TABLE).execute();
}
@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("value");
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);
}
public class SqliteAuthService implements AuthorizationService {
public SqliteAuthService(Connection connection) {
private String authCode(Authorization authorization) {
var code = uuid();
authCodes.put(code, authorization);
return code;
}
@Override
public AuthorizationService authorize(String userId, String clientId, Collection<String> scopes, Instant expiration) {
return null;
try {
conn.setAutoCommit(false);
var stmt = conn.prepareStatement(SAVE_AUTHORIZATION);
stmt.setString(1, userId);
stmt.setString(2, clientId);
stmt.setLong(4, expiration.getEpochSecond());
stmt.setLong(5, expiration.getEpochSecond());
for (var scope : scopes) {
stmt.setString(3, scope);
stmt.execute();
}
conn.commit();
conn.setAutoCommit(true);
return this;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public Optional<Authorization> consumeAuthorization(String authCode) {
return Optional.empty();
return nullable(authCodes.remove(authCode));
}
@Override
public AuthResult getAuthorization(String userId, String clientId, Collection<String> scopes) {
return null;
try {
var scopeList = "(" + scopes.stream().map(s -> "?").collect(Collectors.joining(", ")) + ")";
var sql = SELECT_AUTH + scopeList;
var stmt = conn.prepareStatement(sql);
stmt.setString(1, userId);
stmt.setString(2, clientId);
int i = 3;
for (var scope : scopes) stmt.setString(i++, scope);
var rs = stmt.executeQuery();
var unauthorized = new HashSet<String>(scopes);
var authorized = new HashSet<String>();
var now = Instant.now();
Instant earliestExp = null;
while (rs.next()) {
long expiration = rs.getLong("expiration");
String scope = rs.getString("scope");
Instant ex = Instant.ofEpochSecond(expiration).truncatedTo(ChronoUnit.SECONDS);
if (ex.isAfter(now)) {
unauthorized.remove(scope);
authorized.add(scope);
if (earliestExp == null || ex.isBefore(earliestExp)) earliestExp = ex;
}
}
rs.close();
if (authorized.isEmpty()) return new AuthResult(null, unauthorized, null);
var authorizedScopes = new AuthorizedScopes(authorized, earliestExp);
var authorization = new Authorization(clientId, userId, authorizedScopes);
return new AuthResult(authorizedScopes, unauthorized, authCode(authorization));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

26
de.srsoftware.oidc.datastore.sqlite/src/test/java/de/srsoftware/oidc/datastore/sqlite/SqliteAuthServiceTest.java

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.utils.Strings.uuid;
import de.srsoftware.oidc.api.AuthServiceTest;
import de.srsoftware.oidc.api.AuthorizationService;
import java.io.File;
import java.sql.SQLException;
import org.junit.jupiter.api.BeforeEach;
public class SqliteAuthServiceTest extends AuthServiceTest {
private AuthorizationService authorizationService;
@Override
protected AuthorizationService authorizationService() {
return authorizationService;
}
@BeforeEach
public void setup() throws SQLException {
var dbFile = new File("/tmp/" + uuid() + ".sqlite");
var conn = new ConnectionProvider().get(dbFile);
authorizationService = new SqliteAuthService(conn);
}
}
Loading…
Cancel
Save