preparing client service
Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public record Client(String id, Set<String> redirectUris) {
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ClientService {
|
||||
Optional<Client> getClient(String clientId);
|
||||
ClientService add(Client client);
|
||||
ClientService remove(Client client);
|
||||
ClientService update(Client client);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
public enum Permission {
|
||||
CREATE_CLIENT,
|
||||
ALTER_CLIENT,
|
||||
REMOVE_CLIENT
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
/* © SRSoftware 2024 */
|
||||
package de.srsoftware.oidc.api;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public final class User {
|
||||
public static final String EMAIL = "email";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String PERMISSIONS = "permissions";
|
||||
public static final String REALNAME = "realname";
|
||||
public static final String USERNAME = "username";
|
||||
|
||||
private final Set<Permission> permissions = new HashSet<>();
|
||||
|
||||
private String email, hashedPassword, realName, uuid, username;
|
||||
|
||||
public User(String username, String hashedPassword, String realName, String email, String uuid) {
|
||||
@@ -20,6 +22,11 @@ public final class User {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public User add(Permission permission) {
|
||||
permissions.add(permission);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String email() {
|
||||
return email;
|
||||
}
|
||||
@@ -37,6 +44,10 @@ public final class User {
|
||||
return Objects.equals(this.uuid, that.uuid);
|
||||
}
|
||||
|
||||
public boolean hasPermission(Permission permission){
|
||||
return permissions.contains(permission);
|
||||
}
|
||||
|
||||
public String hashedPassword() {
|
||||
return hashedPassword;
|
||||
}
|
||||
@@ -52,8 +63,10 @@ public final class User {
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> map(boolean includePassword) {
|
||||
return includePassword ? Map.of(USERNAME, username, REALNAME, realName, PASSWORD, hashedPassword, EMAIL, email) : Map.of(USERNAME, username, REALNAME, realName, EMAIL, email);
|
||||
public Map<String, Object> map(boolean includePassword) {
|
||||
return includePassword
|
||||
? Map.of(USERNAME, username, REALNAME, realName, EMAIL, email, PERMISSIONS, permissions, PASSWORD, hashedPassword)
|
||||
: Map.of(USERNAME, username, REALNAME, realName, EMAIL, email, PERMISSIONS, permissions);
|
||||
}
|
||||
|
||||
public String realName() {
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.srsoftware.oidc.app;
|
||||
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import de.srsoftware.oidc.api.ClientService;
|
||||
import de.srsoftware.oidc.api.SessionService;
|
||||
import de.srsoftware.oidc.api.User;
|
||||
import de.srsoftware.oidc.api.UserService;
|
||||
@@ -17,6 +18,8 @@ import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static de.srsoftware.oidc.api.Permission.CREATE_CLIENT;
|
||||
|
||||
public class Application {
|
||||
public static final String BACKEND = "/api";
|
||||
private static final String FAVICON = "/favicon.ico";
|
||||
@@ -35,14 +38,15 @@ public class Application {
|
||||
var storageFile = new File("/tmp/lightoidc.json");
|
||||
var passwordHasher = new UuidHasher();
|
||||
var firstHash = passwordHasher.hash(FIRST_USER_PASS, FIRST_UUID);
|
||||
var firstUser = new User(FIRST_USER, firstHash, FIRST_USER, "%s@internal".formatted(FIRST_USER), FIRST_UUID);
|
||||
var firstUser = new User(FIRST_USER, firstHash, FIRST_USER, "%s@internal".formatted(FIRST_USER), FIRST_UUID).add(CREATE_CLIENT);
|
||||
FileStore fileStore = new FileStore(storageFile, passwordHasher).init(firstUser);
|
||||
UserService userService = fileStore;
|
||||
ClientService clientService = fileStore;
|
||||
SessionService sessionService = fileStore;
|
||||
UserService userService = fileStore;
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
|
||||
new StaticPages(basePath).bindPath(STATIC_PATH, FAVICON).on(server);
|
||||
new Forward(INDEX).bindPath(ROOT).on(server);
|
||||
new Backend(sessionService, userService).bindPath(BACKEND, WELL_KNOWN).on(server);
|
||||
new Backend(clientService, sessionService, userService).bindPath(BACKEND, WELL_KNOWN).on(server);
|
||||
server.setExecutor(Executors.newCachedThreadPool());
|
||||
server.start();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,10 @@ public class Backend extends PathHandler {
|
||||
private static final String REDIRECT_URI = "redirect_uri";
|
||||
private final SessionService sessions;
|
||||
private final UserService users;
|
||||
private final ClientService clients;
|
||||
|
||||
public Backend(SessionService sessionService, UserService userService) {
|
||||
public Backend(ClientService clientService, SessionService sessionService, UserService userService) {
|
||||
clients = clientService;
|
||||
sessions = sessionService;
|
||||
users = userService;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class FileStore implements SessionService, UserService {
|
||||
public class FileStore implements ClientService, SessionService, UserService {
|
||||
private static final String EXPIRATION = "expiration";
|
||||
private static final String SESSIONS = "sessions";
|
||||
private static final String USERS = "users";
|
||||
@@ -54,6 +54,7 @@ public class FileStore implements SessionService, UserService {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public FileStore init(User defaultUser) {
|
||||
if (!json.has(SESSIONS)) json.put(SESSIONS, new JSONObject());
|
||||
@@ -71,8 +72,8 @@ public class FileStore implements SessionService, UserService {
|
||||
public Optional<User> load(String userId) {
|
||||
try {
|
||||
var users = json.getJSONObject(USERS);
|
||||
var user = users.getJSONObject(userId);
|
||||
return Optional.of(new User(user.getString(USERNAME), user.getString(PASSWORD), user.getString(REALNAME), user.getString(EMAIL), userId));
|
||||
var userData = users.getJSONObject(userId);
|
||||
return userOf(userData,userId);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return Optional.empty();
|
||||
@@ -83,12 +84,12 @@ public class FileStore implements SessionService, UserService {
|
||||
try {
|
||||
var users = json.getJSONObject(USERS);
|
||||
var uuids = users.keySet();
|
||||
for (String uuid : uuids) {
|
||||
var user = users.getJSONObject(uuid);
|
||||
if (!user.getString(USERNAME).equals(username)) continue;
|
||||
var hashedPass = user.getString(PASSWORD);
|
||||
for (String userId : uuids) {
|
||||
var userData = users.getJSONObject(userId);
|
||||
if (!userData.getString(USERNAME).equals(username)) continue;
|
||||
var hashedPass = userData.getString(PASSWORD);
|
||||
if (passwordHasher.matches(password, hashedPass)) {
|
||||
return Optional.of(new User(username, hashedPass, user.getString(REALNAME), user.getString(EMAIL), uuid));
|
||||
return userOf(userData,userId);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
@@ -109,6 +110,21 @@ public class FileStore implements SessionService, UserService {
|
||||
return save();
|
||||
}
|
||||
|
||||
private Optional<User> userOf(JSONObject json, String userId){
|
||||
var user = new User(json.getString(USERNAME), json.getString(PASSWORD), json.getString(REALNAME), json.getString(EMAIL), userId);
|
||||
var perms = json.getJSONArray(PERMISSIONS);
|
||||
for (Object perm : perms){
|
||||
try {
|
||||
if (perm instanceof String s) user.add(Permission.valueOf(s));
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.of(user);
|
||||
}
|
||||
|
||||
|
||||
/*** Session Service Methods ***/
|
||||
|
||||
@Override
|
||||
@@ -153,4 +169,25 @@ public class FileStore implements SessionService, UserService {
|
||||
public SessionService setDuration(Duration duration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** client service methods **/
|
||||
@Override
|
||||
public Optional<Client> getClient(String clientId) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientService add(Client client) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientService remove(Client client) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientService update(Client client) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome!</h1>
|
||||
<h2>Connected sites</h2>
|
||||
These are sites that are connected with your account:
|
||||
<h2>Clients</h2>
|
||||
These are clients that are registered with LightOIDC:
|
||||
<table>
|
||||
<tr>
|
||||
<th>Site</th>
|
||||
<th>Client</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user