Browse Source

Merge branch 'devel' into sqlite

sqlite
Stephan Richter 2 months ago
parent
commit
809c4218df
  1. 2
      build.gradle.kts
  2. 6
      de.srsoftware.oidc.api/build.gradle
  3. 2
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java
  4. 6
      de.srsoftware.oidc.app/build.gradle.kts
  5. 5
      de.srsoftware.oidc.backend/build.gradle.kts
  6. 16
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java
  7. 7
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java
  8. 3
      de.srsoftware.oidc.datastore.encrypted/build.gradle.kts
  9. 16
      de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserService.java
  10. 13
      de.srsoftware.oidc.datastore.encrypted/src/test/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserServiceTest.java
  11. 3
      de.srsoftware.oidc.datastore.file/build.gradle.kts
  12. 18
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  13. 1
      de.srsoftware.oidc.datastore.sqlite/build.gradle.kts
  14. 15
      de.srsoftware.oidc.datastore.sqlite/src/main/java/de/srsoftware/oidc/datastore/sqlite/SqliteUserService.java
  15. 3
      de.srsoftware.oidc.web/build.gradle.kts

2
build.gradle.kts

@ -12,7 +12,7 @@ spotless { @@ -12,7 +12,7 @@ spotless {
target("**/src/**/java/**/*.java")
removeUnusedImports()
importOrder()
clangFormat("18.1.8").style("file:config/clang-format")
clangFormat("19.1.7").style("file:config/clang-format")
licenseHeader("/* © SRSoftware 2024 */")
}
}

6
de.srsoftware.oidc.api/build.gradle

@ -2,11 +2,9 @@ @@ -2,11 +2,9 @@
description = 'SRSoftware OIDC: api'
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
implementation 'de.srsoftware:tools.optionals:1.0.0'
implementation 'de.srsoftware:tools.util:1.1.0'
implementation 'de.srsoftware:tools.result:1.0.0'
implementation 'de.srsoftware:tools.util:1.3.1'
implementation 'org.bitbucket.b_c:jose4j:0.9.6'
implementation 'org.json:json:20240303'
implementation 'com.sun.mail:jakarta.mail:2.0.1'

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

@ -6,7 +6,7 @@ import static java.util.Optional.empty; @@ -6,7 +6,7 @@ import static java.util.Optional.empty;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.Lock;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.result.Result;
import java.time.Instant;
import java.util.*;

6
de.srsoftware.oidc.app/build.gradle.kts

@ -7,10 +7,10 @@ plugins { @@ -7,10 +7,10 @@ plugins {
dependencies{
implementation("org.json:json:20240303")
implementation("org.xerial:sqlite-jdbc:3.46.0.0")
implementation("de.srsoftware:tools.http:1.0.1")
implementation("de.srsoftware:tools.logging:1.0.1")
implementation("de.srsoftware:tools.http:1.3.0")
implementation("de.srsoftware:tools.logging:1.2.0")
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.util:1.1.0")
implementation("de.srsoftware:tools.util:1.3.1")
implementation(project(":de.srsoftware.oidc.api"))
implementation(project(":de.srsoftware.oidc.backend"))
implementation(project(":de.srsoftware.oidc.datastore.encrypted"))

5
de.srsoftware.oidc.backend/build.gradle.kts

@ -2,9 +2,10 @@ description = "SRSoftware OIDC: backend" @@ -2,9 +2,10 @@ description = "SRSoftware OIDC: backend"
dependencies{
implementation("com.sun.mail:jakarta.mail:2.0.1")
implementation("de.srsoftware:tools.http:1.0.1")
implementation("de.srsoftware:tools.http:1.3.0")
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.util:1.1.0")
implementation("de.srsoftware:tools.result:1.0.0")
implementation("de.srsoftware:tools.util:1.3.1")
implementation("org.bitbucket.b_c:jose4j:0.9.6")
implementation("org.json:json:20240303")

16
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/ClientController.java

@ -3,6 +3,7 @@ package de.srsoftware.oidc.backend; @@ -3,6 +3,7 @@ package de.srsoftware.oidc.backend;
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.oidc.api.data.Permission.MANAGE_CLIENTS;
import static de.srsoftware.tools.Error.error;
import static java.net.HttpURLConnection.*;
import com.sun.net.httpserver.HttpExchange;
@ -11,7 +12,6 @@ import de.srsoftware.oidc.api.data.AuthorizedScopes; @@ -11,7 +12,6 @@ import de.srsoftware.oidc.api.data.AuthorizedScopes;
import de.srsoftware.oidc.api.data.Client;
import de.srsoftware.oidc.api.data.Session;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Error;
import de.srsoftware.tools.Optionals;
import java.io.IOException;
import java.time.Duration;
@ -42,15 +42,15 @@ public class ClientController extends Controller { @@ -42,15 +42,15 @@ public class ClientController extends Controller {
var user = optUser.get();
var json = json(ex);
var state = json.has(STATE) ? json.getString(STATE) : null;
if (!json.has(CLIENT_ID)) return badRequest(ex, Error.of(ERROR_MISSING_PARAMETER).addData(PARAM, CLIENT_ID, STATE, state));
if (!json.has(CLIENT_ID)) return badRequest(ex, error(ERROR_MISSING_PARAMETER).addData(PARAM, CLIENT_ID, STATE, state));
var clientId = json.getString(CLIENT_ID);
var optClient = clients.getClient(clientId);
if (optClient.isEmpty()) return badRequest(ex, Error.of(ERROR_UNKNOWN_CLIENT).addData(CLIENT_ID, clientId, STATE, state));
if (optClient.isEmpty()) return badRequest(ex, error(ERROR_UNKNOWN_CLIENT).addData(CLIENT_ID, clientId, STATE, state));
for (String param : List.of(SCOPE, RESPONSE_TYPE, REDIRECT_URI)) {
if (!json.has(param)) return badRequest(ex, Error.of(ERROR_MISSING_PARAMETER).addData(PARAM, param, STATE, state));
if (!json.has(param)) return badRequest(ex, error(ERROR_MISSING_PARAMETER).addData(PARAM, param, STATE, state));
}
var scopes = toList(json, SCOPE);
if (!scopes.contains(OPENID)) return badRequest(ex, Error.of(ERROR_MISSING_PARAMETER).addData(PARAM, "Scope: openid", STATE, state));
if (!scopes.contains(OPENID)) return badRequest(ex, error(ERROR_MISSING_PARAMETER).addData(PARAM, "Scope: openid", STATE, state));
var responseTypes = toList(json, RESPONSE_TYPE);
var types = 0;
for (var responseType : responseTypes) {
@ -60,15 +60,15 @@ public class ClientController extends Controller { @@ -60,15 +60,15 @@ public class ClientController extends Controller {
types++;
break;
default:
return badRequest(ex, Error.of(ERROR_UNSUPPORTED_RESPONSE_TYPE).addData(RESPONSE_TYPE, responseType, STATE, state));
return badRequest(ex, error(ERROR_UNSUPPORTED_RESPONSE_TYPE).addData(RESPONSE_TYPE, responseType, STATE, state));
}
}
if (types < 1) return badRequest(ex, Error.of(ERROR_MISSING_CODE_RESPONSE_TYPE).addData(STATE, state));
if (types < 1) return badRequest(ex, error(ERROR_MISSING_CODE_RESPONSE_TYPE).addData(STATE, state));
var client = optClient.get();
var redirect = json.getString(REDIRECT_URI);
if (!client.redirectUris().contains(redirect)) return badRequest(ex, Error.of(ERROR_INVALID_REDIRECT).addData(REDIRECT_URI, redirect, STATE, state));
if (!client.redirectUris().contains(redirect)) return badRequest(ex, error(ERROR_INVALID_REDIRECT).addData(REDIRECT_URI, redirect, STATE, state));
if (json.has(AUTHORZED)) { // user did consent
var authorized = json.getJSONObject(AUTHORZED);

7
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/UserController.java

@ -14,9 +14,8 @@ import de.srsoftware.oidc.api.*; @@ -14,9 +14,8 @@ import de.srsoftware.oidc.api.*;
import de.srsoftware.oidc.api.data.Permission;
import de.srsoftware.oidc.api.data.Session;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.SessionToken;
import de.srsoftware.tools.result.*;
import jakarta.mail.*;
import jakarta.mail.internet.*;
import java.io.IOException;
@ -228,7 +227,7 @@ public class UserController extends Controller { @@ -228,7 +227,7 @@ public class UserController extends Controller {
var user = optUser.get();
users.updatePassword(user, newPass);
var session = sessions.createSession(user, false);
new SessionToken(session.id(), session.expiration(), session.trustBrowser()).addTo(ex);
new SessionToken(session.id(), "/api", session.expiration(), session.trustBrowser()).addTo(ex);
return sendRedirect(ex, "/");
}
@ -267,7 +266,7 @@ public class UserController extends Controller { @@ -267,7 +266,7 @@ public class UserController extends Controller {
}
private boolean sendUserAndCookie(HttpExchange ex, Session session, User user) throws IOException {
new SessionToken(session.id(), session.expiration(), session.trustBrowser()).addTo(ex);
new SessionToken(session.id(), "/api", session.expiration(), session.trustBrowser()).addTo(ex);
return sendContent(ex, user.map(false));
}

3
de.srsoftware.oidc.datastore.encrypted/build.gradle.kts

@ -3,7 +3,8 @@ description = "SRSoftware OIDC: encrypted datastore module" @@ -3,7 +3,8 @@ description = "SRSoftware OIDC: encrypted datastore module"
dependencies{
implementation("com.sun.mail:jakarta.mail:2.0.1")
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.util:1.1.0")
implementation("de.srsoftware:tools.result:1.0.0")
implementation("de.srsoftware:tools.util:1.3.1")
implementation(project(":de.srsoftware.oidc.api"))
testImplementation(project(":de.srsoftware.oidc.api","testBundle"))

16
de.srsoftware.oidc.datastore.encrypted/src/main/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserService.java

@ -2,16 +2,18 @@ @@ -2,16 +2,18 @@
package de.srsoftware.oidc.datastore.encrypted;
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.tools.result.Error.error;
import static java.lang.System.Logger.Level.WARNING;
import static java.util.Optional.empty;
import de.srsoftware.oidc.api.UserService;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Error;
import de.srsoftware.tools.PasswordHasher;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.result.*;
import de.srsoftware.tools.result.Error;
import de.srsoftware.tools.result.Payload;
import de.srsoftware.tools.result.Result;
import java.util.*;
public class EncryptedUserService extends EncryptedConfig implements UserService {
@ -98,12 +100,13 @@ public class EncryptedUserService extends EncryptedConfig implements UserService @@ -98,12 +100,13 @@ public class EncryptedUserService extends EncryptedConfig implements UserService
@Override
public Result<User> login(String username, String password) {
if (username == null || username.isBlank()) return Error.of(ERROR_NO_USERNAME);
if (username == null || username.isBlank()) return error(ERROR_NO_USERNAME);
var optLock = getLock(username);
if (optLock.isPresent()) {
var lock = optLock.get();
LOG.log(WARNING, "{0} is locked after {1} failed logins. Lock will be released at {2}", username, lock.attempts(), lock.releaseTime());
return new Error<User>(ERROR_LOCKED).addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOCKED);
return err.addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
}
for (var encryptedUser : backend.list()) {
var decryptedUser = decrypt(encryptedUser);
@ -116,7 +119,8 @@ public class EncryptedUserService extends EncryptedConfig implements UserService @@ -116,7 +119,8 @@ public class EncryptedUserService extends EncryptedConfig implements UserService
var lock = lock(username);
LOG.log(WARNING, "Login failed for {0} → locking account until {1}", username, lock.releaseTime());
return new Error<User>(ERROR_LOGIN_FAILED).addData(RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOGIN_FAILED);
return err.addData(RELEASE, lock.releaseTime());
}
@Override

13
de.srsoftware.oidc.datastore.encrypted/src/test/java/de/srsoftware/oidc/datastore/encrypted/EncryptedUserServiceTest.java

@ -3,15 +3,16 @@ package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */ @@ -3,15 +3,16 @@ package de.srsoftware.oidc.datastore.encrypted; /* © SRSoftware 2024 */
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.tools.Strings.uuid;
import static de.srsoftware.tools.result.Error.error;
import static java.lang.System.Logger.Level.WARNING;
import de.srsoftware.oidc.api.*;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Error;
import de.srsoftware.tools.PasswordHasher;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.result.Error;
import de.srsoftware.tools.result.Payload;
import de.srsoftware.tools.result.Result;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
@ -76,7 +77,8 @@ public class EncryptedUserServiceTest extends UserServiceTest { @@ -76,7 +77,8 @@ public class EncryptedUserServiceTest extends UserServiceTest {
if (optLock.isPresent()) {
var lock = optLock.get();
LOG.log(WARNING, "{} is locked after {} failed logins. Lock will be released at {}", username, lock.attempts(), lock.releaseTime());
return new Error<User>(ERROR_LOCKED).addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOCKED);
return err.addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
}
for (var entry : users.entrySet()) {
@ -88,7 +90,8 @@ public class EncryptedUserServiceTest extends UserServiceTest { @@ -88,7 +90,8 @@ public class EncryptedUserServiceTest extends UserServiceTest {
}
var lock = lock(username);
LOG.log(WARNING, "Login failed for {0} → locking account until {1}", username, lock.releaseTime());
return new Error<User>(ERROR_LOGIN_FAILED).addData(RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOGIN_FAILED);
return err.addData(RELEASE, lock.releaseTime());
}
@Override

3
de.srsoftware.oidc.datastore.file/build.gradle.kts

@ -3,7 +3,8 @@ description = "SRSoftware OIDC: file datastore module" @@ -3,7 +3,8 @@ description = "SRSoftware OIDC: file datastore module"
dependencies{
implementation("com.sun.mail:jakarta.mail:2.0.1")
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.util:1.1.0")
implementation("de.srsoftware:tools.result:1.0.0")
implementation("de.srsoftware:tools.util:1.3.1")
implementation("org.json:json:20240303")
implementation(project(":de.srsoftware.oidc.api"))

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

@ -4,16 +4,16 @@ import static de.srsoftware.oidc.api.Constants.*; @@ -4,16 +4,16 @@ import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.oidc.api.data.User.*;
import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.tools.Strings.uuid;
import static de.srsoftware.tools.result.Error.error;
import static java.lang.System.Logger.Level.*;
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.util.Optional.empty;
import de.srsoftware.oidc.api.*;
import de.srsoftware.oidc.api.data.*;
import de.srsoftware.tools.Error;
import de.srsoftware.tools.PasswordHasher;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.result.*;
import de.srsoftware.tools.result.Error;
import jakarta.mail.Authenticator;
import jakarta.mail.PasswordAuthentication;
import java.io.File;
@ -181,13 +181,14 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -181,13 +181,14 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
@Override
public Result<User> login(String username, String password) {
if (!json.has(USERS)) return Error.of(ERROR_LOGIN_FAILED);
if (username == null || username.isBlank()) return Error.of(ERROR_NO_USERNAME);
if (!json.has(USERS)) return error(ERROR_LOGIN_FAILED);
if (username == null || username.isBlank()) return error(ERROR_NO_USERNAME);
var optLock = getLock(username);
if (optLock.isPresent()) {
var lock = optLock.get();
LOG.log(WARNING, "{0} is locked after {1} failed logins. Lock will be released at {2}", username, lock.attempts(), lock.releaseTime());
return new Error<User>(ERROR_LOCKED).addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOCKED);
return err.addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
}
try {
var users = json.getJSONObject(USERS);
@ -203,9 +204,10 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe @@ -203,9 +204,10 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
}
var lock = lock(username);
LOG.log(WARNING, "Login failed for {0} → locking account until {1}", username, lock.releaseTime());
return new Error<User>(ERROR_LOGIN_FAILED).addData(RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOGIN_FAILED);
return err.addData(RELEASE, lock.releaseTime());
} catch (Exception e) {
return Error.of(ERROR_LOGIN_FAILED);
return error(ERROR_LOGIN_FAILED);
}
}

1
de.srsoftware.oidc.datastore.sqlite/build.gradle.kts

@ -3,6 +3,7 @@ description = "SRSoftware OIDC: sqlite datastore module" @@ -3,6 +3,7 @@ description = "SRSoftware OIDC: sqlite datastore module"
dependencies{
implementation("com.sun.mail:jakarta.mail:2.0.1")
implementation("de.srsoftware:tools.optionals:1.0.0")
implementation("de.srsoftware:tools.result:1.0.0")
implementation("de.srsoftware:tools.util:1.0.2")
implementation("org.json:json:20240303")
implementation("org.bitbucket.b_c:jose4j:0.9.6")

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

@ -4,6 +4,7 @@ package de.srsoftware.oidc.datastore.sqlite; @@ -4,6 +4,7 @@ package de.srsoftware.oidc.datastore.sqlite;
import static de.srsoftware.oidc.api.Constants.*;
import static de.srsoftware.tools.Optionals.nullable;
import static de.srsoftware.tools.Strings.uuid;
import static de.srsoftware.tools.result.Error.error;
import static java.lang.System.Logger.Level.WARNING;
import static java.util.Optional.empty;
@ -11,10 +12,10 @@ import de.srsoftware.oidc.api.UserService; @@ -11,10 +12,10 @@ import de.srsoftware.oidc.api.UserService;
import de.srsoftware.oidc.api.data.AccessToken;
import de.srsoftware.oidc.api.data.Permission;
import de.srsoftware.oidc.api.data.User;
import de.srsoftware.tools.Error;
import de.srsoftware.tools.PasswordHasher;
import de.srsoftware.tools.Payload;
import de.srsoftware.tools.Result;
import de.srsoftware.tools.result.Error;
import de.srsoftware.tools.result.Payload;
import de.srsoftware.tools.result.Result;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -215,12 +216,13 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -215,12 +216,13 @@ public class SqliteUserService extends SqliteStore implements UserService {
@Override
public Result<User> login(String username, String password) {
if (username == null || username.isBlank()) return Error.message(ERROR_NO_USERNAME);
if (username == null || username.isBlank()) return error(ERROR_NO_USERNAME);
var optLock = getLock(username);
if (optLock.isPresent()) {
var lock = optLock.get();
LOG.log(WARNING, "{0} is locked after {1} failed logins. Lock will be released at {2}", username, lock.attempts(), lock.releaseTime());
return Error.message(ERROR_LOCKED, ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOCKED);
return err.addData(ATTEMPTS, lock.attempts(), RELEASE, lock.releaseTime());
}
for (var user : find(username)) {
if (passwordMatches(password, user)) {
@ -230,7 +232,8 @@ public class SqliteUserService extends SqliteStore implements UserService { @@ -230,7 +232,8 @@ public class SqliteUserService extends SqliteStore implements UserService {
}
var lock = lock(username);
LOG.log(WARNING, "Login failed for {0} → locking account until {1}", username, lock.releaseTime());
return Error.message(ERROR_LOGIN_FAILED, RELEASE, lock.releaseTime());
Error<User> err = error(ERROR_LOGIN_FAILED);
return err.addData(RELEASE, lock.releaseTime());
}
@Override

3
de.srsoftware.oidc.web/build.gradle.kts

@ -1,8 +1,7 @@ @@ -1,8 +1,7 @@
description = "SRSoftware OIDC: web module"
dependencies{
implementation("de.srsoftware:tools.http:1.0.1")
implementation("de.srsoftware:tools.http:1.3.0")
implementation(project(":de.srsoftware.oidc.api"))
}

Loading…
Cancel
Save