[DEV] update with the new back

This commit is contained in:
Edouard DUPIN 2025-01-08 22:47:38 +01:00
parent 24c7f83629
commit cbc0705a79
21 changed files with 592 additions and 355 deletions

View File

@ -11,12 +11,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>

View File

@ -20,17 +20,29 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.11.0</version>
<version>0.20.5-SNAPSHOT</version>
</dependency>
<!-- Loopback of logger JDK logging API to SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.1.0-alpha1</version>
<artifactId>jul-to-slf4j</artifactId>
<version>2.0.9</version>
</dependency>
<!-- generic logger of SLF4J to console (in color) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.1</version>
<version>2.18.0-rc1</version>
</dependency>
<!--
************************************************************
@ -40,15 +52,25 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0-M2</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0-M2</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.24.1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.5.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
@ -166,6 +188,23 @@
<nohelp>true</nohelp>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>org.kar.karso.WebLauncher</mainClass>
</configuration>
</plugin>
<!-- Check the style of the code -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -207,20 +246,20 @@
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>exec-application</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.8.5.0</version>
<configuration>
<mainClass>org.kar.karso.WebLauncher</mainClass>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
<!--<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.12.0</version>
</plugin>
</plugins>
-->
</configuration>
</plugin>
</plugins>

View File

@ -7,18 +7,18 @@ import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.GlobalConfiguration;
import org.kar.archidata.UpdateJwtPublicKey;
import org.kar.archidata.api.DataResource;
import org.kar.archidata.backup.BackupEngine;
import org.kar.archidata.backup.BackupEngine.StoreMode;
import org.kar.archidata.catcher.GenericCatcher;
import org.kar.archidata.db.DBConfig;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.migration.model.Migration;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.ContextGenericTools;
import org.kar.archidata.tools.JWTWrapper;
import org.kar.karso.api.ApplicationResource;
import org.kar.karso.api.ApplicationTokenResource;
@ -47,7 +47,6 @@ import jakarta.ws.rs.core.UriBuilder;
public class WebLauncher {
private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
public static DBConfig dbConfig;
protected UpdateJwtPublicKey keyUpdater = null;
protected HttpServer server = null;
protected BackupEngine backupEngine = new BackupEngine("./backup", StoreMode.JSON);
@ -78,7 +77,7 @@ public class WebLauncher {
migrationEngine.add(new Migration20231126());
migrationEngine.add(new Migration20240515());
WebLauncher.LOGGER.info("Migrate the DB [START]");
migrationEngine.migrateWaitAdmin(GlobalConfiguration.dbConfig);
migrationEngine.migrateWaitAdmin(new DbConfig());
WebLauncher.LOGGER.info("Migrate the DB [STOP]");
}
@ -130,11 +129,13 @@ public class WebLauncher {
rc.register(HealthCheck.class);
rc.register(Front.class);
ContextGenericTools.addJsr310(rc);
// add jackson to be discover when we are ins stand-alone server
rc.register(JacksonFeature.class);
// enable this to show low level request
//rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
LOGGER.info("Start http Server: {}", getBaseURI());
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
final HttpServer serverLink = this.server;
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

View File

@ -6,10 +6,11 @@ import java.util.List;
import java.util.Map;
import org.kar.archidata.annotation.AsyncType;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.exception.SystemException;
@ -96,7 +97,7 @@ public class ApplicationResource {
LOGGER.debug("getApplications");
// TODO filter with the list of element available in his authorizations ...
final List<Application> tmp = DataAccess.gets(Application.class);
if (gc.userByToken.hasRight("ADMIN", true)) {
if (sc.isUserInRole("ADMIN")) {
return tmp;
}
final List<Long> regular = getUserListOfApplication(gc.userByToken.id);
@ -206,7 +207,9 @@ public class ApplicationResource {
@Consumes(MediaType.APPLICATION_JSON)
public void addUser(@PathParam("id") final Long applicationId, final AddUserData data) throws Exception {
LOGGER.debug("getApplications");
AddOnManyToMany.addLink(UserAuth.class, data.userId, "application", applicationId);
try (DBAccess db = DBAccess.createInterface()) {
AddOnManyToMany.addLink(db, UserAuth.class, data.userId, "application", applicationId);
}
}
@DELETE
@ -215,7 +218,9 @@ public class ApplicationResource {
public void removeUser(@PathParam("id") final Long applicationId, @PathParam("userId") final Long userId)
throws Exception {
LOGGER.debug("getApplications");
AddOnManyToMany.removeLink(UserAuth.class, userId, "application", applicationId);
try (DBAccess db = DBAccess.createInterface()) {
AddOnManyToMany.removeLink(db, UserAuth.class, userId, "application", applicationId);
}
}
@GET

View File

@ -63,7 +63,7 @@ public class ApplicationTokenResource {
@Context final SecurityContext sc,
@PathParam("applicationId") final Long applicationId,
@PathParam("tokenId") final Integer tokenId) throws Exception {
final int nbRemoved = DataAccess.deleteWhere(ApplicationToken.class,
final long nbRemoved = DataAccess.deleteWhere(ApplicationToken.class,
new Condition(new QueryAnd(new QueryCondition("parentId", "=", applicationId),
new QueryCondition("id", "=", tokenId))));
if (nbRemoved == 0) {

View File

@ -9,22 +9,32 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryAnd;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.addOn.AddOnManyToMany;
import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.Condition;
import org.kar.archidata.dataAccess.options.ReadAllColumn;
import org.kar.archidata.exception.FailException;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.exception.SystemException;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.tools.JWTWrapper;
import org.kar.karso.migration.Initialization;
import org.kar.karso.model.Application;
import org.kar.karso.model.ChangePassword;
import org.kar.karso.model.ChangePassword.ChangePasswordChecker;
import org.kar.karso.model.DataGetToken;
import org.kar.karso.model.DataGetToken.DataGetTokenChecker;
import org.kar.karso.model.Right;
import org.kar.karso.model.RightDescription;
import org.kar.karso.model.UserAuth;
import org.kar.karso.model.UserAuth.UserAuthChecker;
import org.kar.karso.model.UserAuthGet;
import org.kar.karso.model.UserCreate;
import org.kar.karso.model.UserCreate.UserCreateChecker;
import org.kar.karso.util.ConfigVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -50,6 +60,11 @@ import jakarta.ws.rs.core.SecurityContext;
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {
private static final Logger LOGGER = LoggerFactory.getLogger(UserResource.class);
static final UserAuthChecker CHECKER = new UserAuthChecker();
static final DataGetTokenChecker CHECKER_REQUEST_TOKEN = new DataGetTokenChecker();
static final ChangePasswordChecker CHECKER_CHANGE_PASSWORD = new ChangePasswordChecker();
static final UserCreateChecker CHECKER_CREATE_USER = new UserCreateChecker();
public static final String APPLICATION = "karso";
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class UserOut {
@ -66,16 +81,25 @@ public class UserResource {
@GET
@RolesAllowed("ADMIN")
public List<UserAuthGet> getUsers() throws Exception {
return DataAccess.gets(UserAuthGet.class);
public List<UserAuth> gets() throws Exception {
return DataAccess.gets(UserAuth.class);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public UserAuthGet getUser(@Context final SecurityContext sc, @PathParam("id") final long userId) throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
return DataAccess.get(UserAuthGet.class, userId);
@RolesAllowed({ "ADMIN", "USER" })
public UserAuth get(@Context final SecurityContext sc, @PathParam("id") final long id) throws Exception {
if (!sc.isUserInRole("ADMIN")) {
// in case of user we need to check if it get his own id parameters:
final UserAuth ret = DataAccess.get(UserAuth.class, id, new AccessDeletedItems());
return ret;
}
final UserAuth ret = DataAccess.get(UserAuth.class, id);
if (ret != null) {
return ret;
}
// Find element in deleted
return DataAccess.get(UserAuth.class, id, new AccessDeletedItems(), new ReadAllColumn());
}
@POST
@ -87,12 +111,14 @@ public class UserResource {
@PathParam("applicationId") final long applicationId,
final boolean data) throws Exception {
LOGGER.debug("Find typeNode");
if (data) {
AddOnManyToMany.addLink(UserAuth.class, userId, "application", applicationId);
} else {
AddOnManyToMany.removeLink(UserAuth.class, userId, "application", applicationId);
try (DBAccess db = DBAccess.createInterface()) {
if (data) {
AddOnManyToMany.addLink(db, UserAuth.class, userId, "application", applicationId);
} else {
AddOnManyToMany.removeLink(db, UserAuth.class, userId, "application", applicationId);
}
return db.get(UserAuth.class, userId);
}
return DataAccess.get(UserAuth.class, userId);
}
@GET
@ -126,11 +152,33 @@ public class UserResource {
@Consumes(MediaType.APPLICATION_JSON)
public void setAdmin(@Context final SecurityContext sc, @PathParam("id") final long userId, final boolean data)
throws Exception {
final UserAuth user = new UserAuth();
user.admin = data;
final int ret = DataAccess.update(user, userId, List.of("admin"));
if (ret == 0) {
throw new FailException(Response.Status.NOT_MODIFIED, "Fail to modify user as an admin.");
try (DBAccess da = DBAccess.createInterface()) {
final Application appKarso = da.get(Application.class,
new Condition(new QueryCondition("name", "=", UserResource.APPLICATION)));
final RightDescription rightsDescription = da.get(RightDescription.class,
new Condition(new QueryAnd(new QueryCondition("key", "=", "ADMIN"),
new QueryCondition("applicationId", "=", appKarso.id))));
final Right right = da.get(Right.class,
new Condition(new QueryAnd(new QueryCondition("rightDescriptionId", "=", rightsDescription.id),
new QueryCondition("applicationId", "=", appKarso.id),
new QueryCondition("userId", "=", userId))));
if (right == null) {
final Right newRight = new Right();
newRight.applicationId = appKarso.id;
newRight.userId = userId;
newRight.rightDescriptionId = rightsDescription.id;
newRight.value = "true";
da.insert(newRight);
return;
} else if (right.value.equals("true")) {
return;
}
right.value = "true";
final long ret = da.update(right, right.id, List.of("value"));
if (ret == 0) {
throw new FailException(Response.Status.NOT_MODIFIED, "Fail to modify user as an admin.");
}
}
}
@ -142,7 +190,7 @@ public class UserResource {
throws Exception {
final UserAuth user = new UserAuth();
user.blocked = data;
final int ret = DataAccess.update(user, userId, List.of("blocked"));
final long ret = DataAccess.update(user, userId, List.of("blocked"));
if (ret == 0) {
throw new FailException(Response.Status.NOT_MODIFIED, "Fail to block the User.");
}
@ -153,47 +201,31 @@ public class UserResource {
@Consumes(MediaType.APPLICATION_JSON)
public UserAuthGet create(final UserCreate user) throws Exception {
LOGGER.debug("create new User email={} login={}", user.email, user.login);
// verify login or email is correct:
if (user.login == null || user.login.length() < 6) {
throw new InputException("login", "Authentiocate-method-error (login too small: '" + user.login + "')");
try (DBAccess da = DBAccess.createInterface()) {
CHECKER_CREATE_USER.checkAll(da, "", user, null);
// Check login does not exist
List<UserAuth> out = da.getsWhere(UserAuth.class,
new Condition(new QueryCondition("login", "=", user.login)));
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "Login already used !!!");
}
// Check email does not exist
out = da.getsWhere(UserAuth.class, new Condition(new QueryCondition("email", "=", user.email)));
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "e-mail already used !!!");
}
// Add new user and return formated data.
final UserAuth newUser = new UserAuth();
newUser.blocked = false;
newUser.avatar = false;
newUser.login = user.login;
newUser.password = user.password;
newUser.email = user.email;
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
final UserAuth tmp = da.insert(newUser);
LOGGER.debug("create new user done with id=={}", tmp.id);
return da.get(UserAuthGet.class, tmp.id);
}
// TODO: check login format
if (user.email == null || user.email.length() < 6) {
throw new InputException("email", "Authentiocate-method-error (email too small: '" + user.email + "')");
}
// TODO: check email format
if (user.password == null || user.password.length() != 128) {
throw new InputException("password", "null password, or wrong hash size");
}
// TODO: verify if the data are a hash ...
// Check login does not exist
List<UserAuth> out = DataAccess.getsWhere(UserAuth.class,
new Condition(new QueryCondition("login", "=", user.login)));
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "Login already used !!!");
}
// Check email does not exist
out = DataAccess.getsWhere(UserAuth.class, new Condition(new QueryCondition("email", "=", user.email)));
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "e-mail already used !!!");
}
// Add new user and return formated data.
final UserAuth newUser = new UserAuth();
newUser.admin = false;
newUser.removed = false;
newUser.blocked = false;
newUser.avatar = false;
newUser.login = user.login;
newUser.password = user.password;
newUser.email = user.email;
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
final UserAuth tmp = DataAccess.insert(newUser);
LOGGER.debug("create new user done with id=={}", tmp.id);
return DataAccess.get(UserAuthGet.class, tmp.id);
}
@GET
@ -214,20 +246,19 @@ public class UserResource {
LOGGER.debug("ChangePassword()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.debug("== USER ? {}", gc.userByToken);
if (data == null) {
throw new InputException("data", "No data set...");
try (DBAccess da = DBAccess.createInterface()) {
CHECKER_CHANGE_PASSWORD.checkAll(da, "", data, null);
final UserAuth user = checkAuthUser(data.login, data.time, data.password);
if (user == null) {
throw new SystemException("Fail to retrieve the user... (impossible case)");
}
if (user.id != gc.userByToken.id) {
throw new SystemException("Try to change the password of an other user !!! You are BAD...");
}
// Process the update:
user.password = data.newPassword;
DataAccess.update(user, user.id, List.of("password"));
}
if (data.newPassword == null || data.newPassword.length() != 128) {
throw new InputException("newPassword", "null password, or wrong hash size");
}
final UserAuth user = checkAuthUser(data.method, data.login, data.time, data.password);
if (user == null) {
throw new SystemException("Fail to retrieve the user... (impossible case)");
}
// Process the update:
user.password = data.newPassword;
DataAccess.update(user, user.id, List.of("password"));
}
@GET
@ -251,29 +282,18 @@ public class UserResource {
return out.size() >= 1;
}
private UserAuth checkAuthUser(final String method, final String login, final String time, final String password)
throws Exception {
// check good version:
if (!"v1".contentEquals(method)) {
throw new InputException("method", "Authentiocate-method-error (wrong version: '" + method + "')");
}
// verify login or email is correct:
if (login.length() < 6) {
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");
}
private UserAuth checkAuthUser(final String login, final String time, final String password) throws Exception {
// email or login?
String query = "login";
if (login.contains("@")) {
query = "email";
}
final UserAuth user = DataAccess.getWhere(UserAuth.class, new Condition(new QueryCondition(query, "=", login)));
final UserAuth user = DataAccess.getWhere(UserAuth.class, new Condition(new QueryCondition(query, "=", login)),
new AccessDeletedItems(), new ReadAllColumn());
if (user == null) {
throw new FailException(Response.Status.PRECONDITION_FAILED,
"FAIL Authentiocate-wrong email/login '" + login + "')");
"FAIL Authenticate-wrong email/login '" + login + "')");
}
// Check the password:
final String passwordCheck = getSHA512(
@ -281,9 +301,8 @@ public class UserResource {
if (!passwordCheck.contentEquals(password)) {
throw new FailException(Response.Status.PRECONDITION_FAILED, "Password error ...");
}
LOGGER.debug(" ==> pass nearly all test : admin={} blocked={} removed={}", user.admin, user.blocked,
user.removed);
if (user.blocked || user.removed) {
LOGGER.debug(" ==> pass nearly all test: blocked={} deleted={} ", user.blocked, user.deleted);
if (user.blocked || (user.deleted != null && user.deleted == true)) {
throw new FailException(Response.Status.UNAUTHORIZED, "FAIL Authentiocate");
}
return user;
@ -294,37 +313,36 @@ public class UserResource {
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public GetToken getToken(final DataGetToken data) throws Exception {
LOGGER.info("User Authenticate: {}", data.login());
final UserAuth user = checkAuthUser(data.method(), data.login(), data.time(), data.password());
// at the point the user has been not deleted and not blocked.
// this authentication is valid only for Karso ==> not for the application
final int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime();
// Get the USER Right (Note: by construction KARSO have application ID = KARSO_INITIALISATION_ID
final Map<String, Object> ssoRight = RightResource.getUserRight(user.id,
Initialization.KARSO_INITIALISATION_ID);
if (!ssoRight.containsKey("USER")) {
// If the USER is not override, the system add by default USER
ssoRight.put("USER", true);
LOGGER.info("User Authenticate: {}", data.login);
try (DBAccess da = DBAccess.createInterface()) {
CHECKER_REQUEST_TOKEN.checkAll(da, "", data, null);
final UserAuth user = checkAuthUser(data.login, data.time, data.password);
// at the point the user has been not deleted and not blocked.
// this authentication is valid only for Karso ==> not for the application
final int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime();
// Get the USER Right (Note: by construction KARSO have application ID = KARSO_INITIALISATION_ID
final Map<String, Object> ssoRight = RightResource.getUserRight(user.id,
Initialization.KARSO_INITIALISATION_ID);
if (!ssoRight.containsKey("USER")) {
// If the USER is not override, the system add by default USER
ssoRight.put("USER", true);
}
LOGGER.debug("Get new token with right: {}", ssoRight);
final Map<String, Object> outRight = new HashMap<>();
// we set the right in the under map to manage multiple application group right. and in some application user can see other user or all user of the application
outRight.put(UserResource.APPLICATION, ssoRight);
// TODO: maybe correct this get of TTL...
final String ret = JWTWrapper.generateJWToken(user.id, user.login, "KarAuth", UserResource.APPLICATION,
outRight, expirationTimeInMinutes);
if (ret == null) {
throw new SystemException("Missing internal JWT system ==> can not sign anything ...");
}
// Update last connection:
final UserAuth newUser = new UserAuth();
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
da.update(newUser, user.id, List.of("lastConnection"));
return new GetToken(ret);
}
LOGGER.debug("Get new token with right: {}", ssoRight);
final Map<String, Object> outRight = new HashMap<>();
final String applicationName = "karso";
// we set the right in the under map to manage multiple application group right. and in some application user can see other user or all user of the application
outRight.put(applicationName, ssoRight);
// TODO: maybe correct this get of TTL...
final String ret = JWTWrapper.generateJWToken(user.id, user.login, "KarAuth", applicationName, outRight,
expirationTimeInMinutes);
if (ret == null) {
throw new SystemException("Missing internal JWT system ==> can not sign anything ...");
}
// Update last connection:
final UserAuth newUser = new UserAuth();
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
DataAccess.update(newUser, user.id, List.of("lastConnection"));
//LOGGER.debug(" ==> generate token: {}", ret);
return new GetToken(ret);
}
public static String bytesToHex(final byte[] bytes) {
@ -335,7 +353,7 @@ public class UserResource {
return sb.toString();
}
public String getSHA512(final String passwordToHash) {
public static String getSHA512(final String passwordToHash) {
try {
final MessageDigest md = MessageDigest.getInstance("SHA-512");
final byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));

View File

@ -2,10 +2,13 @@ package org.kar.karso.filter;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.Map;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.filter.AuthenticationFilter;
import org.kar.archidata.filter.PartRight;
import org.kar.archidata.model.UserByToken;
import org.kar.karso.api.UserResource;
import org.kar.karso.model.ApplicationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -23,7 +26,7 @@ public class KarsoAuthenticationFilter extends AuthenticationFilter {
//curl http://0.0.0.0:15080/karso/api/public_key/pem --output plop.txt -H "Authorization: Zota 1:U0sJM1m@-STSdfg4365fJOFUGbR4kFycBu1qGZPwf7gW6k2WWRBzTPUH7QutCgPw-SDss45_563sSDFdfg@dsf@456" --verbose
public KarsoAuthenticationFilter() {
super("karso");
super(UserResource.APPLICATION);
}
@Override
@ -64,7 +67,8 @@ public class KarsoAuthenticationFilter extends AuthenticationFilter {
userByToken.name = value.name;
userByToken.parentId = value.parentId;
userByToken.type = UserByToken.TYPE_APPLICATION;
userByToken.right.put("APPLICATION", true);
// TODO: Manage the retrieve of specific rights ...
userByToken.right.put(UserResource.APPLICATION, Map.of("APPLICATION", PartRight.READ_WRITE));
return userByToken;
}
}

View File

@ -2,9 +2,10 @@ package org.kar.karso.migration;
import java.util.List;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.addOnSQL.AddOnManyToMany;
import org.kar.archidata.migration.MigrationSqlStep;
import org.kar.archidata.tools.UuidUtils;
import org.kar.karso.api.UserResource;
import org.kar.karso.model.Application;
import org.kar.karso.model.ApplicationToken;
import org.kar.karso.model.Right;
@ -19,62 +20,90 @@ public class Initialization extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
public static final List<Class<?>> LIST_OF_COMMON_CLASSES = List.of(Settings.class, UserAuth.class,
Application.class, ApplicationToken.class, RightDescription.class, Right.class);
public static final List<Class<?>> CLASSES_BASE = List.of(Settings.class, UserAuth.class, Application.class,
ApplicationToken.class, RightDescription.class, Right.class);
// created object
private Application app = null;
private UserAuth user = null;
private RightDescription rightDescription;
@Override
public String getName() {
return "Initialization";
}
public Initialization() {
}
@Override
public void generateStep() throws Exception {
for (final Class<?> clazz : LIST_OF_COMMON_CLASSES) {
for (final Class<?> clazz : CLASSES_BASE) {
addClass(clazz);
}
addAction(
"""
INSERT INTO `application` (`id`, `name`, `description`, `redirect`, `redirectDev`, `notification`, `ttl`) VALUES
(1, 'karso', 'Root SSO interface', 'http://atria-soft/karso', '', '', 666);
""");
addAction((final DBAccess da) -> {
final Application app = new Application();
//app.id = 1L;
app.name = "karso";
app.description = "Root SSO interface";
app.redirect = "https://atria-soft/karso";
app.redirectDev = "http://localhost:4003/karso";
app.notification = "";
app.ttl = 666;
this.app = da.insert(app);
});
// default admin: "karadmin" password: "adminA@666"
addAction(
"""
INSERT INTO `user` (`id`, `login`, `password`, `email`, `admin`) VALUES
(1, 'karadmin', '0ddcac5ede3f1300a1ce5948ab15112f2810130531d578ab8bc4dc131652d7cf7a3ff6e827eb957bff43bc2c65a6a1d46722e5b3a2343ac3176a33ea7250080b',
'admin@admin.ZZZ', 1);
""");
final String data = UuidUtils.nextUUID().toString();
addAction("""
INSERT INTO `user_link_application` (`uuid`, `object1Id`, `object2Id`)
VALUES (UUID_TO_BIN('%s'), '1', '1');
""".formatted(data), "mysql");
addAction("""
INSERT INTO `user_link_application` (`uuid`, `object1Id`, `object2Id`)
VALUES ('%s', '1', '1');
""".formatted(data), "sqlite");
addAction("""
INSERT INTO `settings` (`key`, `right`, `type`, `value`) VALUES
('SIGN_UP_ENABLE', 'rwr-r-', 'BOOLEAN', 'false'),
('SIGN_IN_ENABLE', 'rwr-r-', 'BOOLEAN', 'true'),
('SIGN_UP_FILTER', 'rw----', 'STRING', '.*'),
('EMAIL_VALIDATION_REQUIRED', 'rwr-r-', 'BOOLEAN', 'false');
""");
addAction(
"""
INSERT INTO `rightDescription` (`id`, `applicationId`, `key`, `title`, `description`, `type`, `defaultValue`) VALUES
(1, 1, 'ADMIN', 'Administrator', 'Full administrator Right', 'BOOLEAN', 'false');
""");
addAction("""
INSERT INTO `right` (`applicationId`, `userId`, `rightDescriptionId`, `value`) VALUES
(1, 1, 1, 'true');
""");
// we generate an offset to permit to manage some generic upgrade in the future... (can not be done in sqlite)
addAction((final DBAccess da) -> {
final UserAuth user = new UserAuth();
//user.id = 1L;
user.login = "karadmin";
user.password = UserResource.getSHA512("adminA@666");
user.email = "admin@admin.ZZZ";
this.user = da.insert(user);
});
addAction((final DBAccess da) -> {
AddOnManyToMany.addLink(da, UserAuth.class, this.user.id, "application", this.app.id);
});
addAction((final DBAccess da) -> {
final Settings settings = new Settings();
settings.key = "SIGN_UP_ENABLE";
settings.right = "rwr-r-";
settings.type = "BOOLEAN";
settings.value = "false";
da.insert(settings);
settings.key = "SIGN_IN_ENABLE";
settings.right = "rwr-r-";
settings.type = "BOOLEAN";
settings.value = "true";
da.insert(settings);
settings.key = "SIGN_UP_FILTER";
settings.right = "rw----";
settings.type = "STRING";
settings.value = ".*";
da.insert(settings);
settings.key = "EMAIL_VALIDATION_REQUIRED";
settings.right = "rwr-r-";
settings.type = "BOOLEAN";
settings.value = "false";
da.insert(settings);
});
addAction((final DBAccess da) -> {
final RightDescription rightDescription = new RightDescription();
rightDescription.applicationId = this.app.id;
rightDescription.key = "ADMIN";
rightDescription.title = "Administrator";
rightDescription.description = "Full administrator Right";
rightDescription.type = "BOOLEAN";
rightDescription.defaultValue = "false";
this.rightDescription = da.insert(rightDescription);
});
addAction((final DBAccess da) -> {
final Right right = new Right();
right.applicationId = this.app.id;
right.userId = this.user.id;
right.rightDescriptionId = this.rightDescription.id;
right.value = "true";
da.insert(right);
});
// we generate an offset to permit to manage some generic upgrade in the future...
addAction("""
ALTER TABLE `application` AUTO_INCREMENT = 1000;
""", "mysql");
@ -93,10 +122,10 @@ public class Initialization extends MigrationSqlStep {
display();
}
public static void dropAll() {
for (final Class<?> element : LIST_OF_COMMON_CLASSES) {
public static void dropAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
DataAccess.drop(element);
da.drop(element);
} catch (final Exception ex) {
LOGGER.error("Fail to drop table !!!!!!");
ex.printStackTrace();
@ -104,10 +133,10 @@ public class Initialization extends MigrationSqlStep {
}
}
public static void cleanAll() {
for (final Class<?> element : LIST_OF_COMMON_CLASSES) {
public static void cleanAll(final DBAccess da) {
for (final Class<?> element : CLASSES_BASE) {
try {
DataAccess.cleanAll(element);
da.cleanAll(element);
} catch (final Exception ex) {
LOGGER.error("Fail to clean table !!!!!!");
ex.printStackTrace();

View File

@ -2,7 +2,7 @@ package org.kar.karso.migration;
import java.util.List;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.dataAccess.options.AccessDeletedItems;
import org.kar.archidata.dataAccess.options.OverrideTableName;
import org.kar.archidata.migration.MigrationSqlStep;
@ -28,14 +28,14 @@ public class Migration20240515 extends MigrationSqlStep {
addAction("""
ALTER TABLE `user_link_application` ADD `uuid` binary(16) AFTER `id`;
""");
addAction(() -> {
final List<UUIDConversion> datas = DataAccess.gets(UUIDConversion.class, new AccessDeletedItems(),
addAction((final DBAccess da) -> {
final List<UUIDConversion> datas = da.gets(UUIDConversion.class, new AccessDeletedItems(),
new OverrideTableName("user_link_application"));
for (final UUIDConversion elem : datas) {
elem.uuid = UuidUtils.nextUUID();
}
for (final UUIDConversion elem : datas) {
DataAccess.update(elem, elem.id, List.of("uuid"), new OverrideTableName("user_link_application"));
da.update(elem, elem.id, List.of("uuid"), new OverrideTableName("user_link_application"));
}
});
addAction("""

View File

@ -1,21 +1,11 @@
package org.kar.karso.model;
/*
CREATE TABLE `application` (
`id` bigint NOT NULL COMMENT 'Unique ID of the application' AUTO_INCREMENT PRIMARY KEY,
`description` text COMMENT 'description of the application',
`token` varchar(128) COLLATE 'latin1_bin' NOT NULL COMMENT 'Token (can be not unique)'
) AUTO_INCREMENT=10;
*/
import org.kar.archidata.annotation.DataComment;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.model.GenericDataSoftDelete;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
import jakarta.ws.rs.DefaultValue;
@ -37,11 +27,11 @@ public class Application extends GenericDataSoftDelete {
@DefaultValue("'http://localhost:4200/sso/notification'")
public String notification;
@Column(nullable = false)
@DataComment("Expiration time ")
@Schema(description = "Expiration time ")
@DefaultValue("666")
public Integer ttl;
@Column(nullable = false)
@DataComment("Right is manage with Karso")
@Schema(description = "Right is manage with Karso")
@DefaultValue("0")
public Boolean manageRight;

View File

@ -1,19 +1,39 @@
package org.kar.karso.model;
import org.kar.archidata.dataAccess.options.CheckJPA;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ChangePassword {
@Column(length = 32)
@NotNull
@Size(min = 2, max = 2)
@Pattern(regexp = "^v1$")
public String method;
@Column(length = 512)
@NotNull
@Size(min = 3, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-_ \\.@]+$")
public String login;
@Column(length = 64)
@NotNull
@Size(min = 20, max = 64)
@Pattern(regexp = "^\\d{4}\\-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,9})+.*$")
public String time;
@Column(length = 128)
@NotNull
@Size(min = 128, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9]{128}$")
public String password;
@Column(length = 128)
@NotNull
@Size(min = 128, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9]{128}$")
public String newPassword;
public static class ChangePasswordChecker extends CheckJPA<ChangePassword> {
public ChangePasswordChecker() {
super(ChangePassword.class);
}
}
}

View File

@ -3,21 +3,53 @@ package org.kar.karso.model;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.kar.archidata.dataAccess.options.CheckJPA;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record DataGetToken(
String login,
String method,
String time,
String password) {
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
/*public DataGetToken(String login, String method,
String time,
String password) {
this(login, method, time, password);
}*/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DataGetToken {
@NotNull
@Size(min = 3, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-_ \\.@]+$")
public String login;
@NotNull
@Size(min = 2, max = 2)
@Pattern(regexp = "^v1$")
public String method;
@NotNull
@Size(min = 20, max = 64)
@Pattern(regexp = "^\\d{4}\\-\\d{2}\\-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,9})+.*$")
public String time;
@NotNull
@Size(min = 128, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9]{128}$")
public String password;
public static class DataGetTokenChecker extends CheckJPA<DataGetToken> {
public DataGetTokenChecker() {
super(DataGetToken.class);
}
}
public DataGetToken(final String login, final String password, final String time, final String method) {
this.method = method;
this.login = login;
this.time = time;
this.password = password;
}
public DataGetToken() {
}
public static String sha512(final String passwordToHash) { //, String salt){
String generatedPassword = null;
@ -36,20 +68,28 @@ public record DataGetToken(
return generatedPassword;
}
public static DataGetToken generate(final String login, final String password) {
return generate(login, password, ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT));
}
public static DataGetToken generate(final String login, final String password, final String time) {
return generate(login, password, time, "v1");
}
public static DataGetToken generate(
final String login,
final String method,
final String password,
final String time,
final String password) {
return generateSha(login, method, time, sha512(password));
final String method) {
return generateSha(login, sha512(password), time, method);
}
public static DataGetToken generateSha(
final String login,
final String method,
final String password,
final String time,
final String password) {
return new DataGetToken(login, method, time,
sha512("login='" + login + "';pass='" + password + "';date='" + time + "'"));
final String method) {
return new DataGetToken(login, sha512("login='" + login + "';pass='" + password + "';date='" + time + "'"),
time, method);
}
}

View File

@ -4,6 +4,7 @@ import java.sql.Timestamp;
import java.util.List;
import org.kar.archidata.annotation.DataIfNotExists;
import org.kar.archidata.dataAccess.options.CheckJPA;
import org.kar.archidata.model.User;
import com.fasterxml.jackson.annotation.JsonInclude;
@ -12,6 +13,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import jakarta.ws.rs.DefaultValue;
@Table(name = "user")
@ -19,6 +22,8 @@ import jakarta.ws.rs.DefaultValue;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserAuth extends User {
@Column(length = 128, nullable = false)
@Size(min = 128, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9]{128}$")
public String password;
/*
@Column(length = 128)
@ -27,9 +32,13 @@ public class UserAuth extends User {
public String passwordValidation; //!< UniqueId to validate the new password
*/
@Column(length = 512, nullable = false)
@Size(min = 5, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-\\._]+@[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9]+$")
public String email;
public Timestamp emailValidate; // time of validation
@Column(length = 512)
@Size(min = 5, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-\\._]+@[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9]+$")
public String newEmail;
@DefaultValue("'0'")
@Column(nullable = false)
@ -38,4 +47,10 @@ public class UserAuth extends User {
@ManyToMany(targetEntity = Application.class)
public List<Long> applications = null;
public static class UserAuthChecker extends CheckJPA<UserAuth> {
public UserAuthChecker() {
super(UserAuth.class);
}
}
}

View File

@ -1,10 +1,31 @@
package org.kar.karso.model;
import org.kar.archidata.dataAccess.options.CheckJPA;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserCreate {
@NotNull
@Size(min = 3, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-_ \\.@]+$")
public String login;
@NotNull
@Size(min = 5, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9\\-\\._]+@[a-zA-Z0-9\\-_]+\\.[a-zA-Z0-9]+$")
public String email;
@NotNull
@Size(min = 128, max = 128)
@Pattern(regexp = "^[a-zA-Z0-9]{128}$")
public String password;
public static class UserCreateChecker extends CheckJPA<UserCreate> {
public UserCreateChecker() {
super(UserCreate.class);
}
}
}

View File

@ -0,0 +1,13 @@
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern name="ConversionPattern">
%green(%d{HH:mm:ss.SSS}) %highlight(%-5level) %-30((%file:%line\)): %msg%n
</pattern>
</encoder>
</appender>
<root level="trace">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@ -1,35 +0,0 @@
# SLF4J's SimpleLogger configuration file
# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err.
# Default logging detail level for all instances of SimpleLogger.
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, defaults to "info".
org.slf4j.simpleLogger.defaultLogLevel=trace
# Logging detail level for a SimpleLogger instance named "xxxxx".
# Must be one of ("trace", "debug", "info", "warn", or "error").
# If not specified, the default logging detail level is used.
#org.slf4j.simpleLogger.log.xxxxx=
# Set to true if you want the current date and time to be included in output messages.
# Default is false, and will output the number of milliseconds elapsed since startup.
#org.slf4j.simpleLogger.showDateTime=false
# The date and time format to be used in the output messages.
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat.
# If the format is not specified or is invalid, the default format is used.
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z.
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z
# Set to true if you want to output the current thread name.
# Defaults to true.
org.slf4j.simpleLogger.showThreadName=true
# Set to true if you want the Logger instance name to be included in output messages.
# Defaults to true.
#org.slf4j.simpleLogger.showLogName=true
# Set to true if you want the last component of the name to be included in output messages.
# Defaults to false.
#org.slf4j.simpleLogger.showShortLogName=false

View File

@ -0,0 +1,126 @@
package test.kar.karso;
import java.io.IOException;
import java.util.List;
import org.kar.archidata.dataAccess.DBAccess;
import org.kar.archidata.db.DbConfig;
import org.kar.archidata.db.DbIoFactory;
import org.kar.archidata.exception.DataAccessException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.karso.api.RightResource;
import org.kar.karso.model.Application;
import org.kar.karso.model.Right;
import org.kar.karso.model.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.InternalServerErrorException;
public class ConfigureDb {
final static private Logger LOGGER = LoggerFactory.getLogger(ConfigureDb.class);
final static private String modeTestForced = null;// "MONGO";
public static DBAccess da = null;
public static void configure() throws IOException, InternalServerErrorException, DataAccessException {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12342/test/api/";
// Enable the test mode permit to access to the test token (never use it in production).
ConfigBaseVariable.testMode = "true";
final List<Class<?>> listObject = List.of( //
Application.class, //
RightResource.class, //
Right.class, //
Settings.class //
);
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.bdDatabase = null;
ConfigBaseVariable.dbKeepConnected = "true";
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mysql";
ConfigBaseVariable.bdDatabase = "test_karso_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
ConfigBaseVariable.dbType = "mongo";
ConfigBaseVariable.bdDatabase = "test_karso_db";
} else {
// User local modification ...
ConfigBaseVariable.bdDatabase = "test_karso_db";
ConfigBaseVariable.dbPort = "3906";
ConfigBaseVariable.dbUser = "root";
}
removeDB();
// Connect the dataBase...
da = DBAccess.createInterface();
}
public static void removeDB() {
String modeTest = System.getenv("TEST_E2E_MODE");
if (modeTest == null || modeTest.isEmpty() || "false".equalsIgnoreCase(modeTest)) {
modeTest = "SQLITE-MEMORY";
} else if ("true".equalsIgnoreCase(modeTest)) {
modeTest = "MY-SQL";
}
// override the local test:
if (modeTestForced != null) {
modeTest = modeTestForced;
}
DbConfig config = null;
try {
config = new DbConfig();
} catch (final DataAccessException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
config.setDbName(null);
LOGGER.info("Remove the DB and create a new one '{}'", config.getDbName());
try (final DBAccess daRoot = DBAccess.createInterface(config)) {
if ("SQLITE-MEMORY".equalsIgnoreCase(modeTest)) {
// nothing to do ...
} else if ("SQLITE".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MY-SQL".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
} else if ("MONGO".equalsIgnoreCase(modeTest)) {
daRoot.deleteDB(ConfigBaseVariable.bdDatabase);
}
daRoot.createDB(ConfigBaseVariable.bdDatabase);
} catch (final InternalServerErrorException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
} catch (final IOException e) {
e.printStackTrace();
LOGGER.error("Fail to clean the DB");
return;
}
}
public static void clear() throws IOException {
LOGGER.info("Remove the test db");
removeDB();
// The connection is by default open ==> close it at the end of test:
da.close();
DbIoFactory.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
}
}

View File

@ -11,7 +11,6 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.JWTWrapper;
@ -32,8 +31,7 @@ public class TestBase {
public void login(final String login, final String password) {
try {
final GetToken token = api.post(GetToken.class, "users/get_token",
DataGetToken.generate(login, "v1", "202515252", password));
final GetToken token = api.post(GetToken.class, "users/get_token", DataGetToken.generate(login, password));
api.setToken(token.jwt);
} catch (final Exception ex) {
Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage());
@ -46,15 +44,10 @@ public class TestBase {
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
@ -66,17 +59,14 @@ public class TestBase {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
Thread.sleep(1000);
ConfigureDb.clear();
}
@Order(3)
@Test
public void firstUserConnect() throws Exception {
final GetToken result = api.post(GetToken.class, "users/get_token",
DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
DataGetToken.generate("karadmin", "adminA@666", "2025-15-25T22:32:23.252Z"));
final String[] splitted = result.jwt.split("\\.");
Assertions.assertEquals(3, splitted.length);
final String authorization = result.jwt;

View File

@ -10,8 +10,7 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.RESTErrorResponseExeption;
import org.kar.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.kar.karso.api.HealthCheck.HealthResult;
@ -28,15 +27,10 @@ public class TestHealthCheck {
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
@ -48,10 +42,7 @@ public class TestHealthCheck {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
Thread.sleep(1000);
ConfigureDb.clear();
}
@Order(1)
@ -65,7 +56,7 @@ public class TestHealthCheck {
@Order(2)
@Test
public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseExeption.class, () -> api.get(HealthResult.class, "health_checks"));
Assertions.assertThrows(RESTErrorResponseException.class, () -> api.get(HealthResult.class, "health_checks"));
}
}

View File

@ -9,8 +9,7 @@ import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.RESTErrorResponseExeption;
import org.kar.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
@ -27,8 +26,7 @@ public class TestUnAuthorizedAPI {
public void login(final String login, final String password) {
try {
final GetToken token = api.post(GetToken.class, "users/get_token",
DataGetToken.generate(login, "v1", "202515252", password));
final GetToken token = api.post(GetToken.class, "users/get_token", DataGetToken.generate(login, password));
api.setToken(token.jwt);
} catch (final Exception ex) {
Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage());
@ -41,15 +39,10 @@ public class TestUnAuthorizedAPI {
@BeforeAll
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
@ -61,10 +54,7 @@ public class TestUnAuthorizedAPI {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
Thread.sleep(1000);
ConfigureDb.clear();
}
public void checkFail(final String type, final String urlOffset, final int errorStatus) {
@ -84,7 +74,7 @@ public class TestUnAuthorizedAPI {
api.delete(String.class, urlOffset);
}
Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (final RESTErrorResponseExeption ex) {
} catch (final RESTErrorResponseException ex) {
if (errorStatus != ex.status) {
LOGGER.error("Fail in test with the wrong return errors: {}", ex.toString());
}
@ -113,7 +103,7 @@ public class TestUnAuthorizedAPI {
api.delete(String.class, urlOffset);
}
//Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (final RESTErrorResponseExeption ex) {
} catch (final RESTErrorResponseException ex) {
Assertions.fail("Must not fail ... " + ex.toString());
} catch (final Exception ex) {
LOGGER.error("Unexpected throw error: {}", ex);

View File

@ -11,12 +11,10 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;
import org.kar.archidata.db.DBEntry;
import org.kar.archidata.exception.RESTErrorResponseExeption;
import org.kar.archidata.exception.RESTErrorResponseException;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.tools.ConfigBaseVariable;
import org.kar.archidata.tools.RESTApi;
import org.kar.karso.migration.Initialization;
import org.kar.karso.model.DataGetToken;
import org.kar.karso.model.UserAuthGet;
import org.slf4j.Logger;
@ -34,32 +32,17 @@ public class TestUsers {
private static long idTest;
@BeforeAll
public static void configureWebServer() throws InterruptedException, RESTErrorResponseExeption, IOException {
public static void configureWebServer() throws Exception {
ConfigureDb.configure();
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
LOGGER.info("Clean previous table");
try {
Initialization.dropAll();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("plop: {}", ex.getLocalizedMessage());
throw ex;
}
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
webInterface.migrateDB();
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
final GetToken result = api.post(GetToken.class, "users/get_token",
DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
DataGetToken.generate("karadmin", "adminA@666"));
api.setToken(result.jwt);
}
@ -68,19 +51,16 @@ public class TestUsers {
LOGGER.info("Kill the web server");
webInterface.stop();
webInterface = null;
LOGGER.info("Remove the test db");
DBEntry.closeAllForceMode();
ConfigBaseVariable.clearAllValue();
ConfigureDb.clear();
}
@Order(1)
@Test
public void getsValue() throws RESTErrorResponseExeption, IOException, InterruptedException {
public void getsValue() throws RESTErrorResponseException, IOException, InterruptedException {
final List<UserAuthGet> listUsers = api.gets(UserAuthGet.class, TestUsers.ENDPOINT_NAME);
Assertions.assertNotNull(listUsers);
Assertions.assertEquals(1, listUsers.size());
Assertions.assertEquals(1, listUsers.get(0).id);
Assertions.assertEquals(true, listUsers.get(0).admin);
Assertions.assertEquals(false, listUsers.get(0).blocked);
Assertions.assertEquals(false, listUsers.get(0).avatar);
Assertions.assertEquals("karadmin", listUsers.get(0).login);