[DEV] some back upgrade and add password change (no return GUI)

This commit is contained in:
Edouard DUPIN 2023-01-05 00:13:10 +01:00
parent ca8274295e
commit f3ae1fcd1c
12 changed files with 140 additions and 85 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId> <groupId>org.kar</groupId>
<artifactId>karso</artifactId> <artifactId>karso</artifactId>
<version>0.1.0</version> <version>0.2.0</version>
<properties> <properties>
<!-- <!--
<jaxb.version>2.3.1</jaxb.version> <jaxb.version>2.3.1</jaxb.version>
@ -27,7 +27,7 @@
<dependency> <dependency>
<groupId>kangaroo-and-rabbit</groupId> <groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId> <artifactId>archidata</artifactId>
<version>0.2.1</version> <version>0.2.2</version>
</dependency> </dependency>
<!-- testing --> <!-- testing -->
<dependency> <dependency>

View File

@ -72,6 +72,7 @@ public class WebLauncher {
rc.register(SystemExceptionCatcher.class); rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class); rc.register(FailExceptionCatcher.class);
rc.register(ExceptionCatcher.class); rc.register(ExceptionCatcher.class);
// add default resource: // add default resource:
rc.registerClasses(UserResource.class); rc.registerClasses(UserResource.class);
rc.registerClasses(PublicKeyResource.class); rc.registerClasses(PublicKeyResource.class);

View File

@ -55,9 +55,6 @@ public class ApplicationResource {
@Path("get_token") @Path("get_token")
@RolesAllowed(value= {"USER", "ADMIN"}) @RolesAllowed(value= {"USER", "ADMIN"})
public Response getClientToken(@Context SecurityContext sc, @QueryParam("application") String application) { public Response getClientToken(@Context SecurityContext sc, @QueryParam("application") String application) {
System.out.println("=====================================");
System.out.println("Get client Token()");
System.out.println("=====================================");
GenericContext gc = (GenericContext) sc.getUserPrincipal(); GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("== USER ? " + gc.user); System.out.println("== USER ? " + gc.user);

View File

@ -1,19 +1,15 @@
package org.kar.karso.api; package org.kar.karso.api;
import org.kar.archidata.SqlWrapper; import org.kar.archidata.SqlWrapper;
import org.kar.archidata.filter.GenericContext;
import org.kar.karso.model.*; import org.kar.karso.model.*;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.kar.archidata.util.JWTWrapper;
import org.kar.archidata.annotation.security.PermitAll; import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.RolesAllowed; import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.NotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.ws.rs.*; import javax.ws.rs.*;
@ -23,46 +19,46 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.SecurityContext;
@Path("/system_config") @Path("/system_config")
@Produces( MediaType.APPLICATION_JSON) @Produces( MediaType.APPLICATION_JSON)
public class SystemConfigResource { public class SystemConfigResource {
public static class GetSignUpAvaillable {
public boolean signup;
public GetSignUpAvaillable(boolean availlable) {
this.signup = availlable;
}
public GetSignUpAvaillable() {
signup = false;
}
}
public SystemConfigResource() { public SystemConfigResource() {
} }
@GET @GET
@Path("is_sign_up_availlable") @Path("is_sign_up_availlable")
@PermitAll @PermitAll
public Response isSignUpAvaillable() { public GetSignUpAvaillable isSignUpAvaillable() throws Exception {
Settings set = null; Settings set = SqlWrapper.getWhere(Settings.class, "key", "=", "SIGN_UP_ENABLE", false);
try { if (set == null) {
set = SqlWrapper.getWhere(Settings.class, "key", "=", "SIGN_UP_ENABLE"); throw new NotFoundException("Value does not exist");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
System.out.println(" result: " + result);
return Response.status(500).entity(result).build();
} }
System.out.println(" get data: " + set);
boolean availlable = "true".equalsIgnoreCase(set.value); boolean availlable = "true".equalsIgnoreCase(set.value);
return Response.status(200).entity("{ \"signup\":" + availlable + "}").build(); GetSignUpAvaillable tmp = new GetSignUpAvaillable(availlable);
System.out.println("mlkmlk " + tmp.signup);
return tmp;
} }
@GET @GET
@Path("key/{key}") @Path("key/{key}")
@RolesAllowed(value= {"USER", "ADMIN"}) @RolesAllowed(value= {"USER", "ADMIN"})
public Response getKey(@Context SecurityContext sc, @PathParam("key") String key) { public Response getKey(@Context SecurityContext sc, @PathParam("key") String key) throws Exception {
Settings set = null; Settings set = SqlWrapper.getWhere(Settings.class, "key", "=", key, false);
try { if (set == null) {
set = SqlWrapper.getWhere(Settings.class, "key", "=", key); throw new NotFoundException("Value does not exist");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "Can not find the Key";
return Response.status(404).entity(result).build();
} }
if (set.type.equals("BOOLEAN")) { if (set.type.equals("BOOLEAN")) {
boolean availlable = "true".equalsIgnoreCase(set.value); boolean availlable = "true".equalsIgnoreCase(set.value);
@ -81,7 +77,7 @@ public class SystemConfigResource {
public Response setKey(@Context SecurityContext sc, @PathParam("key") String key, String jsonRequest) throws Exception { public Response setKey(@Context SecurityContext sc, @PathParam("key") String key, String jsonRequest) throws Exception {
Settings res = null; Settings res = null;
try { try {
res = SqlWrapper.getWhere(Settings.class, "key", "=", key); res = SqlWrapper.getWhere(Settings.class, "key", "=", key, false);
} catch (Exception e) { } catch (Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -95,7 +91,7 @@ public class SystemConfigResource {
res.value = value.asText(); res.value = value.asText();
SqlWrapper.update(res, res.id, Arrays.asList("value")); SqlWrapper.update(res, res.id, List.of("value"));
return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build(); return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build();
} }

View File

@ -2,10 +2,8 @@ package org.kar.karso.api;
import org.kar.archidata.model.GetToken; import org.kar.archidata.model.GetToken;
import org.kar.archidata.model.User; import org.kar.archidata.model.User;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.SqlWrapper; import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition; import org.kar.archidata.WhereCondition;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.FailException; import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException; import org.kar.archidata.exception.InputException;
import org.kar.archidata.exception.SystemException; import org.kar.archidata.exception.SystemException;
@ -22,10 +20,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.SecurityContext;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -38,14 +32,12 @@ public class UserResource {
public UserResource() { public UserResource() {
} }
// curl http://localhost:9993/api/users
@GET @GET
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
public List<UserAuth> getUsers() throws Exception { public List<UserAuth> getUsers() throws Exception {
return SqlWrapper.gets(UserAuth.class, false); return SqlWrapper.gets(UserAuth.class, false);
} }
// curl http://localhost:9993/api/users/3
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed("ADMIN") @RolesAllowed("ADMIN")
@ -102,29 +94,19 @@ public class UserResource {
if(data == null) { if(data == null) {
throw new InputException("data", "No data set..."); throw new InputException("data", "No data set...");
} }
if(data.password == null) { if(data.newPassword == null || data.newPassword.length() != 128) {
throw new InputException("password", "null password"); throw new InputException("newPassword", "null password, or wrong hash size");
} }
if(data.password.length() != 128) { UserAuth user = checkAuthUser(data.method, data.login, data.time, data.password);
throw new InputException("password", "password has not the correct hash size");
}
// TODO: check every char are in the range 0-9a-f
// with security level 1: (No e-mail system)
UserAuth user = SqlWrapper.get(UserAuth.class, gc.user.id);
if (user == null) { if (user == null) {
throw new SystemException("Fail to retrieve the user... (impossible case)"); throw new SystemException("Fail to retrieve the user... (impossible case)");
} }
user.password = data.password; // Process the update:
SqlWrapper.update(user, gc.user.id, List.of("password")); user.password = data.newPassword;
SqlWrapper.update(user, user.id, List.of("password"));
return Response.status(Response.Status.OK).build(); return Response.status(Response.Status.OK).build();
// With security level 2:
// TODO: Set the new password in the passwordChange
// TODO: set a uniqueID in the correct passwordValidation zone
// TODO: Set the data in the BDD
// TODO: send an e-mail
} }
/* /*
@GET @GET
@Path("validipass") @Path("validipass")
@ -156,6 +138,7 @@ public class UserResource {
return Response.status(404).build(); return Response.status(404).build();
} }
// TODO: add an application TOKEN and permit only 50 requested (maybe add an option to disable it).
@GET @GET
@Path("/check_email") @Path("/check_email")
@PermitAll @PermitAll
@ -170,46 +153,53 @@ public class UserResource {
return Response.status(404).build(); return Response.status(404).build();
} }
@POST
@Path("/get_token") private UserAuth checkAuthUser(String method, String login, String time, String password) throws Exception {
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public GetToken getToken(DataGetToken data) throws Exception {
System.out.println("login: " + data.login );
// check good version: // check good version:
if (!data.method.contentEquals("v1")) { if (!"v1".contentEquals(method)) {
throw new InputException("method", "Authentiocate-method-error (wrong version: '" + data.method + "')"); throw new InputException("method", "Authentiocate-method-error (wrong version: '" + method + "')");
} }
// verify login or email is correct: // verify login or email is correct:
if (data.login.length() < 6) { if (login.length() < 6) {
throw new InputException("login", "Authentiocate-method-error (email or login too small: '" + data.login + "')"); throw new InputException("login", "Authentiocate-method-error (email or login too small: '" + login + "')");
} }
if(password == null || password.length() != 128) {
throw new InputException("password", "null password, or wrong hash size");
}
// email or login? // email or login?
String query = "login"; String query = "login";
if (data.login.contains("@")) { if (login.contains("@")) {
query = "email"; query = "email";
} }
UserAuth user = SqlWrapper.getWhere(UserAuth.class, UserAuth user = SqlWrapper.getWhere(UserAuth.class,
List.of( List.of(
new WhereCondition(query, "=", data.login) new WhereCondition(query, "=", login)
), ),
false ); false );
if (user == null) { if (user == null) {
throw new FailException(Response.Status.PRECONDITION_FAILED , "FAIL Authentiocate-wrong email/login '" + data.login + "')"); throw new FailException(Response.Status.PRECONDITION_FAILED , "FAIL Authentiocate-wrong email/login '" + login + "')");
} }
// Check the password: // Check the password:
String passwodCheck = getSHA512("login='" + data.login + "';pass='" + user.password + "';date='" + data.time + "'"); String passwodCheck = getSHA512("login='" + login + "';pass='" + user.password + "';date='" + time + "'");
if (!passwodCheck.contentEquals(data.password)) { if (!passwodCheck.contentEquals(password)) {
throw new FailException(Response.Status.PRECONDITION_FAILED , "Password error ..."); throw new FailException(Response.Status.PRECONDITION_FAILED , "Password error ...");
} }
System.out.println(" ==> pass nearly all test : admin=" + user.admin + " blocked=" + user.blocked + " removed=" + user.removed); System.out.println(" ==> pass nearly all test : admin=" + user.admin + " blocked=" + user.blocked + " removed=" + user.removed);
if (user.blocked || user.removed) { if (user.blocked || user.removed) {
throw new FailException(Response.Status.UNAUTHORIZED, "FAIL Authentiocate"); throw new FailException(Response.Status.UNAUTHORIZED, "FAIL Authentiocate");
} }
int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime(); return user;
}
String ret = JWTWrapper.generateJWToken(user.id, user.login, ".", "sso", expirationTimeInMinutes); @POST
@Path("/get_token")
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public GetToken getToken(DataGetToken data) throws Exception {
UserAuth user = checkAuthUser(data.method, data.login, data.time, data.password);
int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime();
String ret = JWTWrapper.generateJWToken(user.id, user.login, "KarAuth", "sso", expirationTimeInMinutes);
//System.out.println(" ==> generate token: " + ret); //System.out.println(" ==> generate token: " + ret);
return new GetToken(ret); return new GetToken(ret);
} }

View File

@ -1,5 +1,9 @@
package org.kar.karso.model; package org.kar.karso.model;
public class ChangePassword { public class ChangePassword {
public String method;
public String login;
public String time;
public String password; public String password;
public String newPassword;
} }

View File

@ -38,7 +38,7 @@ public class Settings extends GenericTable {
@SQLComment("Right for the specific element(ADMIN [rw] USER [rw] other [rw])") @SQLComment("Right for the specific element(ADMIN [rw] USER [rw] other [rw])")
@SQLNotNull @SQLNotNull
@SQLLimitSize(6) @SQLLimitSize(6)
@SQLDefault("rw----") @SQLDefault("\"rw----\"")
public String right; public String right;
@SQLComment("Type Of the data") @SQLComment("Type Of the data")
@SQLNotNull @SQLNotNull

View File

@ -6,7 +6,7 @@
[style.border]="hasError? '2px dashed red' : ''" [style.border]="hasError? '2px dashed red' : ''"
[value]="value" [value]="value"
(input)="onChangeValue($event.target.value)" /> (input)="onChangeValue($event.target.value)" />
<button class="eye-button" (click)="onVisibility()" type="submit"> <button class="eye-button unselectable" tabindex="-1" (click)="onVisibility()" type="submit">
<i class="material-icons">{{passwordVisibility?"visibility":"visibility_off"}}</i> <i class="material-icons">{{passwordVisibility?"visibility":"visibility_off"}}</i>
</button> </button>
</div> </div>

View File

@ -32,6 +32,7 @@
img.avatar { img.avatar {
width: 150px; width: 150px;
border-radius: 50%; border-radius: 50%;
user-select: none;
} }
.container-global { .container-global {

View File

@ -7,6 +7,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { createPasswordState } from 'common/utils'; import { createPasswordState } from 'common/utils';
import { AdminUserService } from 'app/service';
@Component({ @Component({
selector: 'app-change-password', selector: 'app-change-password',
@ -26,7 +27,8 @@ export class ChangePasswordScene {
public validateButtonDisabled: boolean = true; public validateButtonDisabled: boolean = true;
constructor( constructor(
private locate: Location private locate: Location,
private adminUserService: AdminUserService
) {} ) {}
/** /**
* update the state of the validation button. if all is OK, the button will became clickable * update the state of the validation button. if all is OK, the button will became clickable
@ -85,7 +87,13 @@ export class ChangePasswordScene {
* Summit change password. * Summit change password.
*/ */
onChangePassword(): void { onChangePassword(): void {
this.adminUserService.changePassword(this.passwordOld, this.password1)
.then(() => {
console.log(`Change password is OK`);
})
.catch((error: any) => {
console.error(`Fail to change PAssword: ${error}`);
});
} }
/** /**
* Apply cancel on this page * Apply cancel on this page

View File

@ -37,7 +37,10 @@ export class AdminUserService {
// 0: Not hide password; 1 hide password; // 0: Not hide password; 1 hide password;
private identificationVersion: number = 1; private identificationVersion: number = 1;
constructor(private userService: UserService, private http: HttpWrapperService) { constructor(
private userService: UserService,
private sessionService: SessionService,
private http: HttpWrapperService) {
console.log('Start AdminUserService'); console.log('Start AdminUserService');
} }
/** /**
@ -215,4 +218,50 @@ export class AdminUserService {
retreivePassword(login: string): Promise<void> { retreivePassword(login: string): Promise<void> {
throw new Error('retreivePassword: Method not implemented.'); throw new Error('retreivePassword: Method not implemented.');
} }
changePassword(oldPassword: string, newPassword: string): Promise<void> {
let time: string = new Date().toISOString();
let login: string = this.sessionService.getLogin();
let method = null;
let password = null;
if (this.identificationVersion === 1) {
method = 'v1';
password = sha512(`login='${login}';pass='${sha512(oldPassword)}';date='${time}'`);
} else {
return new Promise((resolve, reject) => {
reject(`Internal Fail (contact administrator).`);
});
}
let body = {
method,
time,
login,
password,
newPassword: sha512(newPassword),
}
let self = this;
return new Promise((resolve, reject) => {
self.http
.request({
server: 'karso',
endPoint: 'users/password',
requestType: HTTPRequestModel.POST,
accept: HTTPMimeType.JSON,
contentType: HTTPMimeType.JSON,
body,
})
.then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
console.log(`Update password done with sucess`);
resolve();
} else {
reject(`return ERROR to change password: ${response.status}`);
}
})
.catch((error: any) => {
reject(`return ERROR ${JSON.stringify(error, null, 2)}`);
});
});
}
} }

View File

@ -252,6 +252,15 @@ label {
user-select: none; user-select: none;
} }
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.fill-x { .fill-x {
width: 100%; width: 100%;
} }