Browse Source

working on user settings

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
sqlite
Stephan Richter 7 months ago
parent
commit
f078491344
  1. 2
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/Client.java
  2. 20
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java
  3. 5
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/User.java
  4. 2
      de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/UserService.java
  5. 39
      de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java
  6. 17
      de.srsoftware.oidc.datastore.file/src/main/java/de/srsoftware/oidc/datastore/file/FileStore.java
  7. 26
      de.srsoftware.oidc.web/src/main/resources/en/common.js
  8. 4
      de.srsoftware.oidc.web/src/main/resources/en/index.html
  9. 4
      de.srsoftware.oidc.web/src/main/resources/en/login.js
  10. 5
      de.srsoftware.oidc.web/src/main/resources/en/navigation.html
  11. 55
      de.srsoftware.oidc.web/src/main/resources/en/settings.html
  12. 68
      de.srsoftware.oidc.web/src/main/resources/en/settings.js
  13. 22
      de.srsoftware.oidc.web/src/main/resources/en/user.js

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

@ -2,5 +2,5 @@ package de.srsoftware.oidc.api; @@ -2,5 +2,5 @@ package de.srsoftware.oidc.api;
import java.util.Set;
public record Client(String id, String name, Set<String> redirectUris) {
public record Client(String id, String name, String secret, Set<String> redirectUris) {
}

20
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/PathHandler.java

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
/* © SRSoftware 2024 */
package de.srsoftware.oidc.api;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -8,6 +9,7 @@ import com.sun.net.httpserver.HttpExchange; @@ -8,6 +9,7 @@ import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@ -106,13 +108,25 @@ public abstract class PathHandler implements HttpHandler { @@ -106,13 +108,25 @@ public abstract class PathHandler implements HttpHandler {
return false;
}
public static boolean sendContent(HttpExchange ex, byte[] bytes) throws IOException {
ex.sendResponseHeaders(HTTP_OK, bytes.length);
public static boolean sendContent(HttpExchange ex, int status, byte[] bytes) throws IOException {
ex.sendResponseHeaders(status, bytes.length);
ex.getResponseBody().write(bytes);
return true;
}
public static boolean sendContent(HttpExchange ex, byte[] bytes) throws IOException {
return sendContent(ex,HTTP_OK,bytes);
}
public static boolean sendContent(HttpExchange ex, Object o) throws IOException {
return sendContent(ex, o.toString().getBytes(UTF_8));
return sendContent(ex, HTTP_OK, o.toString().getBytes(UTF_8));
}
public static boolean sendError(HttpExchange ex, byte[] bytes) throws IOException {
return sendContent(ex,HTTP_BAD_REQUEST,bytes);
}
public static boolean sendError(HttpExchange ex, Object o) throws IOException {
return sendContent(ex,HTTP_BAD_REQUEST,o.toString().getBytes(UTF_8));
}
}

5
de.srsoftware.oidc.api/src/main/java/de/srsoftware/oidc/api/User.java

@ -9,6 +9,7 @@ public final class User { @@ -9,6 +9,7 @@ public final class User {
public static final String PERMISSIONS = "permissions";
public static final String REALNAME = "realname";
public static final String USERNAME = "username";
public static final String UUID = "uuid";
private final Set<Permission> permissions = new HashSet<>();
@ -65,8 +66,8 @@ public final class User { @@ -65,8 +66,8 @@ public final class User {
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);
? Map.of(USERNAME, username, REALNAME, realName, EMAIL, email, PERMISSIONS, permissions, UUID, uuid, PASSWORD, hashedPassword)
: Map.of(USERNAME, username, REALNAME, realName, EMAIL, email, PERMISSIONS, permissions, UUID, uuid);
}
public String realName() {

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

@ -6,9 +6,11 @@ import java.util.Optional; @@ -6,9 +6,11 @@ import java.util.Optional;
public interface UserService {
public UserService delete(User user);
public boolean passwordMatches(String password, String hashedPassword);
public UserService init(User defaultUser);
public List<User> list();
public Optional<User> load(String id);
public Optional<User> load(String username, String password);
public <T extends UserService> T save(User user);
public <T extends UserService> T updatePassword(User user, String plaintextPassword);
}

39
de.srsoftware.oidc.backend/src/main/java/de/srsoftware/oidc/backend/Backend.java

@ -2,8 +2,7 @@ @@ -2,8 +2,7 @@
package de.srsoftware.oidc.backend;
import static de.srsoftware.oidc.api.Permission.MANAGE_CLIENTS;
import static de.srsoftware.oidc.api.User.PASSWORD;
import static de.srsoftware.oidc.api.User.USERNAME;
import static de.srsoftware.oidc.api.User.*;
import static java.net.HttpURLConnection.*;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -11,6 +10,7 @@ import com.sun.net.httpserver.HttpExchange; @@ -11,6 +10,7 @@ import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.cookies.SessionToken;
import de.srsoftware.oidc.api.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
@ -83,6 +83,10 @@ public class Backend extends PathHandler { @@ -83,6 +83,10 @@ public class Backend extends PathHandler {
return authorize(ex,session);
case "/clients":
return clients(ex,session);
case "/update/password":
return updatePassword(ex,session);
case "/update/user":
return updateUser(ex,session);
case "/user":
return sendUserAndCookie(ex, session);
}
@ -114,4 +118,35 @@ public class Backend extends PathHandler { @@ -114,4 +118,35 @@ public class Backend extends PathHandler {
out.write(bytes);
return true;
}
private boolean updatePassword(HttpExchange ex, Session session) throws IOException {
var user =session.user();
var json = json(ex);
var uuid = json.getString(UUID);
if (!uuid.equals(user.uuid())) {
return sendEmptyResponse(HTTP_FORBIDDEN, ex);
}
var oldPass = json.getJSONArray("oldpass");
var oldPass1 = oldPass.getString(0);
if (!oldPass1.equals(oldPass.getString(1))){
return sendError(ex,"password mismatch");
}
if (!users.passwordMatches(oldPass1,user.hashedPassword())) return sendError(ex,"wrong password");
users.updatePassword(user,json.getString("newpass"));
return sendContent(ex,new JSONObject(user.map(false)));
}
private boolean updateUser(HttpExchange ex, Session session) throws IOException {
var user =session.user();
var json = json(ex);
var uuid = json.getString(UUID);
if (!uuid.equals(user.uuid())){
return sendEmptyResponse(HTTP_FORBIDDEN,ex);
}
user.username(json.getString(USERNAME));
user.email(json.getString(EMAIL));
users.save(user);
JSONObject response = new JSONObject(user.map(false));
return sendContent(ex,response);
}
}

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

@ -62,6 +62,8 @@ public class FileStore implements ClientService, SessionService, UserService { @@ -62,6 +62,8 @@ public class FileStore implements ClientService, SessionService, UserService {
return this;
}
@Override
public List<User> list() {
return List.of();
@ -98,6 +100,11 @@ public class FileStore implements ClientService, SessionService, UserService { @@ -98,6 +100,11 @@ public class FileStore implements ClientService, SessionService, UserService {
}
}
@Override
public boolean passwordMatches(String password, String hashedPassword) {
return passwordHasher.matches(password,hashedPassword);
}
@Override
public FileStore save(User user) {
JSONObject users;
@ -110,6 +117,14 @@ public class FileStore implements ClientService, SessionService, UserService { @@ -110,6 +117,14 @@ public class FileStore implements ClientService, SessionService, UserService {
return save();
}
@Override
public FileStore updatePassword(User user, String plaintextPassword) {
var oldHashedPassword = user.hashedPassword();
var salt = passwordHasher.salt(oldHashedPassword);
user.hashedPassword(passwordHasher.hash(plaintextPassword,salt));
return save(user);
}
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);
@ -132,7 +147,7 @@ public class FileStore implements ClientService, SessionService, UserService { @@ -132,7 +147,7 @@ public class FileStore implements ClientService, SessionService, UserService {
public Session createSession(User user) {
var now = Instant.now();
var endOfSession = now.plus(sessionDuration);
return save(new Session(user, endOfSession, UUID.randomUUID().toString()));
return save(new Session(user, endOfSession, java.util.UUID.randomUUID().toString()));
}
@Override

26
de.srsoftware.oidc.web/src/main/resources/en/common.js

@ -2,3 +2,29 @@ var api = "/api"; @@ -2,3 +2,29 @@ var api = "/api";
var web = "/web";
const UNAUTHORIZED = 401;
function get(id){
return document.getElementById(id);
}
function disable(id){
get(id).setAttribute('disabled',true);
}
function enable(id){
get(id).removeAttribute('disabled');
}
function getValue(id){
return get(id).value;
}
function setText(id, text){
get(id).innerHTML = text;
}
function setValue(id,newVal){
document.getElementById(id).value = newVal;
}

4
de.srsoftware.oidc.web/src/main/resources/en/index.html

@ -6,9 +6,7 @@ @@ -6,9 +6,7 @@
<script src="user.js"></script>
</head>
<body>
<nav>
<a id="clients" href="clients.html">Clients</a>
</nav>
<nav></nav>
<h1>Welcome!</h1>
</body>
</html>

4
de.srsoftware.oidc.web/src/main/resources/en/login.js

@ -16,8 +16,8 @@ function doRedirect(){ @@ -16,8 +16,8 @@ function doRedirect(){
function tryLogin(){
document.getElementById("error").innerHTML = "";
var username = document.getElementById('username').value;
var password = document.getElementById('password').value;
var username = getValue('username');
var password = getValue('password');
fetch(api+"/login",{
method: 'POST',
headers: {

5
de.srsoftware.oidc.web/src/main/resources/en/navigation.html

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
<a href="index.html">Dashboard</a>
<a href="clients.html" class="MANAGE_CLIENTS">Clients</a>
<a href="users.html" class="MANAGE_USERS">Users</a>
<a href="settings.html">Settings</a>
<a href="logout.html">Logout</a>

55
de.srsoftware.oidc.web/src/main/resources/en/settings.html

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
<html>
<head>
<meta charset="utf-8">
<title>Light OIDC</title>
<script src="common.js"></script>
<script src="user.js"></script>
<script src="settings.js"></script>
</head>
<body>
<nav></nav>
<h1>Settings</h1>
<form>
<fieldset>
<legend>
Basic settings
</legend>
<table>
<tr>
<th>User name</th>
<td><input id="username" type="text"></td>
</tr>
<tr>
<th>Email</th>
<td><input id="email" type="email"></td>
</tr>
<tr>
<th>ID</th>
<td><input id="uuid" type="text" disabled="true"></td>
</tr>
</table>
<button id="updateBtn" type="button" onClick="update()">Update</button>
</fieldset>
<fieldset>
<legend>
Password
</legend>
<table>
<tr>
<th>Old password</th>
<td><input id="oldpass1" type="password"></td>
</tr>
<tr>
<th>Repeat Password</th>
<td><input id="oldpass2" type="password"></td>
</tr>
<tr>
<th>New Password</th>
<td><input id="newpass" type="password"></td>
</tr>
</table>
<button id="passBtn" type="button" onClick="updatePass()">Update</button>
</fieldset>
</form>
</body>
</html>

68
de.srsoftware.oidc.web/src/main/resources/en/settings.js

@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
function fillForm(){
if (user == null){
setTimeout(fillForm,100);
} else {
console.log(user);
setValue('username',user.username);
setValue('email',user.email);
setValue('uuid', user.uuid);
}
}
function handleResponse(response){
setText('updateBtn',response.ok ? 'saved.' : 'failed!');
setTimeout(function(){
setText('updateBtn','Update');
enable('updateBtn');
},10000);
}
function handlePasswordResponse(response){
setText('passBtn',response.ok ? 'saved.' : 'failed!');
setTimeout(function(){
setText('passBtn','Update');
enable('passBtn');
},10000);
}
function update(){
disable('updateBtn');
setText('updateBtn','sent…');
var newData = {
username : getValue('username'),
email : getValue('email'),
uuid : getValue('uuid')
}
fetch(api+'/update/user',{
method : 'POST',
headers : {
'Content-Type': 'application/json'
},
body : JSON.stringify(newData)
}).then(handleResponse)
}
function updatePass(){
disable('passBtn');
setText('passBtn','sent…');
var newData = {
oldpass : [getValue('oldpass1'),getValue('oldpass2')],
newpass : getValue('newpass'),
uuid : getValue('uuid')
}
fetch(api+'/update/password',{
method : 'POST',
headers : {
'Content-Type': 'application/json'
},
body : JSON.stringify(newData)
}).then(handlePasswordResponse);
setTimeout(function(){
setText('passBtn','Update');
enable('passBtn');
},10000);
}
setTimeout(fillForm,100);

22
de.srsoftware.oidc.web/src/main/resources/en/user.js

@ -1,11 +1,27 @@ @@ -1,11 +1,27 @@
var user = null;
async function handleUser(response){
if (response.status == UNAUTHORIZED) {
window.location.href = 'login.html?return_to='+encodeURI(window.location.href);
return;
}
var user = await response.json();
// TODO: load navigation
if (response.ok){
user = await response.json();
fetch(web+"/navigation.html").then(handleNavigation);
}
}
async function handleNavigation(response){
if (response.ok){
var content = await response.text();
var nav = document.getElementsByTagName('nav')[0];
nav.innerHTML = content;
var links = nav.getElementsByTagName('a');
for (var index = 0; index < links.length; index++){
var link = links[index];
var clazz = link.hasAttribute('class') ? link.getAttribute("class") : null;
if (clazz != null && !user.permissions.includes(clazz)) nav.removeChild(link);
}
}
}
fetch(api+"/user",{method:'POST'}).then(handleUser);
Loading…
Cancel
Save