[DEV] review with new model

This commit is contained in:
Edouard DUPIN 2023-10-14 12:22:21 +02:00
parent f4d7438918
commit 4f8a34590e
22 changed files with 996 additions and 1116 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="out/maven/classes" path="src">
<classpathentry including="**/*.java" kind="src" output="out/maven/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
@ -13,11 +13,6 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
@ -25,10 +20,16 @@
</classpathentry>
<classpathentry excluding="**" kind="src" output="out/maven/test-classes" path="test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="out/maven/classes"/>
</classpath>

View File

@ -1,5 +1,5 @@
services:
db_service:
kar_db_service:
image: mysql:latest
restart: always
environment:
@ -9,20 +9,20 @@ services:
#- /workspace/data/global/db:/var/lib/mysql
mem_limit: 300m
ports:
- 3306:3306
- 3906:3306
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 10s
retries: 5
start_period: 20s
adminer_service:
kar_adminer_service:
image: adminer:latest
restart: always
ports:
- 10079:8080
- 18079:8080
links:
- db_service:db
- kar_db_service:db
#read_only: true
mem_limit: 100m

View File

@ -24,7 +24,7 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.3.7</version>
<version>0.4.0</version>
</dependency>
<!-- testing -->
<dependency>
@ -159,7 +159,25 @@
<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>
</plugins>
<testResources>
<testResource>
<directory>${basedir}/test/resources</directory>

View File

@ -1,8 +1,25 @@
package org.kar.karso;
import java.net.URI;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.kar.archidata.GlobalConfiguration;
//import org.kar.archidata.model.Migration;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailException404API;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.filter.OptionFilter;
import org.kar.archidata.migration.MigrationEngine;
import org.kar.archidata.sqlWrapper.GenericAddOn;
import org.kar.archidata.util.ConfigBaseVariable;
import org.kar.archidata.util.JWTWrapper;
import org.kar.karso.api.ApplicationResource;
import org.kar.karso.api.ApplicationTokenResource;
import org.kar.karso.api.Front;
@ -16,38 +33,26 @@ import org.kar.karso.migration.Initialization;
import org.kar.karso.util.ConfigVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kar.archidata.GlobalConfiguration;
//import org.kar.archidata.model.Migration;
import org.kar.archidata.catcher.ExceptionCatcher;
import org.kar.archidata.catcher.FailException404API;
import org.kar.archidata.catcher.FailExceptionCatcher;
import org.kar.archidata.catcher.InputExceptionCatcher;
import org.kar.archidata.catcher.SystemExceptionCatcher;
import org.kar.archidata.filter.CORSFilter;
import org.kar.archidata.util.ConfigBaseVariable;
import org.kar.archidata.util.JWTWrapper;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.core.UriBuilder;
import java.net.URI;
public class WebLauncher {
final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
private final static Logger LOGGER = LoggerFactory.getLogger(WebLauncher.class);
protected ResourceConfig rc = null;
HttpServer server = null;
public WebLauncher() {
ConfigBaseVariable.bdDatabase = "karso";
GenericAddOn.addGenericAddOn();
}
private static URI getBaseURI() {
return UriBuilder.fromUri(ConfigBaseVariable.getlocalAddress()).build();
}
public static void main(String[] args) throws Exception {
public static void main(final String[] args) throws Exception {
WebLauncher.LOGGER.info("[START] application wake UP");
WebLauncher launcher = new WebLauncher();
final WebLauncher launcher = new WebLauncher();
launcher.migrateDB();
launcher.process();
@ -58,7 +63,7 @@ public class WebLauncher {
public void migrateDB() throws Exception {
WebLauncher.LOGGER.info("Create migration engine");
MigrationEngine migrationEngine = new MigrationEngine();
final MigrationEngine migrationEngine = new MigrationEngine();
WebLauncher.LOGGER.info("Add initialization");
migrationEngine.setInit(new Initialization());
WebLauncher.LOGGER.info("Add migration since last version");
@ -71,7 +76,7 @@ public class WebLauncher {
public void process() throws InterruptedException {
try {
JWTWrapper.initLocalToken(ConfigVariable.getUUIDKeyRoot());
} catch (Exception e1) {
} catch (final Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
LOGGER.info("Wait 10 seconds ....");
@ -82,47 +87,47 @@ public class WebLauncher {
// ===================================================================
// Configure resources
// ===================================================================
rc = new ResourceConfig();
// global authentication system
rc.register(OptionFilter.class);
rc.register(CORSFilter.class);
rc.register(KarsoAuthenticationFilter.class);
// register exception catcher
rc.register(InputExceptionCatcher.class);
rc.register(SystemExceptionCatcher.class);
rc.register(FailExceptionCatcher.class);
rc.register(FailException404API.class);
rc.register(ExceptionCatcher.class);
this.rc = new ResourceConfig();
// global authentication system
this.rc.register(OptionFilter.class);
this.rc.register(CORSFilter.class);
this.rc.register(KarsoAuthenticationFilter.class);
// register exception catcher
this.rc.register(InputExceptionCatcher.class);
this.rc.register(SystemExceptionCatcher.class);
this.rc.register(FailExceptionCatcher.class);
this.rc.register(FailException404API.class);
this.rc.register(ExceptionCatcher.class);
// add default resource:
rc.register(UserResource.class);
rc.register(PublicKeyResource.class);
rc.register(ApplicationResource.class);
rc.register(ApplicationTokenResource.class);
rc.register(SystemConfigResource.class);
rc.register(RightResource.class);
rc.register(Front.class);
rc.register(HealthCheck.class);
this.rc.register(UserResource.class);
this.rc.register(PublicKeyResource.class);
this.rc.register(ApplicationResource.class);
this.rc.register(ApplicationTokenResource.class);
this.rc.register(SystemConfigResource.class);
this.rc.register(RightResource.class);
this.rc.register(Front.class);
this.rc.register(HealthCheck.class);
// add jackson to be discover when we are ins stand-alone server
rc.register(JacksonFeature.class);
// enable this to show low level request
this.rc.register(JacksonFeature.class);
// enable this to show low level request
//rc.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_SERVER, Level.WARNING.getName());
server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), rc);
this.server = GrizzlyHttpServerFactory.createHttpServer(getBaseURI(), this.rc);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
LOGGER.info("Stopping server..");
server.shutdownNow();
WebLauncher.this.server.shutdownNow();
}
}, "shutdownHook"));
// ===================================================================
// ===================================================================
// run JERSEY
// ===================================================================
// ===================================================================
try {
server.start();
this.server.start();
LOGGER.info("Jersey app started at {}", getBaseURI());
} catch (Exception e) {
} catch (final Exception e) {
LOGGER.error("There was an error while starting Grizzly HTTP server.");
e.printStackTrace();
}

View File

@ -7,36 +7,39 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WebLauncherLocal extends WebLauncher {
final Logger logger = LoggerFactory.getLogger(WebLauncherLocal.class);
private static final Logger LOGGER = LoggerFactory.getLogger(WebLauncherLocal.class);
private WebLauncherLocal() {}
public static void main(String[] args) throws InterruptedException {
WebLauncherLocal launcher = new WebLauncherLocal();
public static void main(final String[] args) throws InterruptedException {
final WebLauncherLocal launcher = new WebLauncherLocal();
launcher.process();
launcher.logger.info("end-configure the server & wait finish process:");
LOGGER.info("end-configure the server & wait finish process:");
Thread.currentThread().join();
launcher.logger.info("STOP the REST server:");
LOGGER.info("STOP the REST server:");
}
@Override
public void process() throws InterruptedException {
if (true) {
// for local test:
ConfigBaseVariable.apiAdress = "http://0.0.0.0:15080/karso/api/";
ConfigBaseVariable.dbPort = "3306";
ConfigBaseVariable.dbPort = "3906";
// create a unique key for test ==> not retrieve the token every load...
ConfigVariable.uuid_for_key_generation = "lkjlkjlkjlmkjqmwlsdkjqfsdlkf88QJSDMLQKSndmLQKZNERMAL";
//ConfigBaseVariable.dbType = "sqlite";
//ConfigBaseVariable.dbHost = "./bdd_base.sqlite";
}
try {
super.migrateDB();
} catch (Exception e) {
// TODO Auto-generated catch block
} catch (final Exception e) {
e.printStackTrace();
while (true) {
logger.error("Migration fail ==> waiting intervention of administrator...");
Thread.sleep(60*60*1000);
LOGGER.error("============================================================================");
LOGGER.error("== Migration fail ==> waiting intervention of administrator...");
LOGGER.error("============================================================================");
Thread.sleep(60 * 60 * 1000);
}
}
super.process();

View File

@ -1,107 +1,113 @@
package org.kar.karso.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.archidata.filter.GenericContext;
import org.kar.karso.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kar.archidata.util.JWTWrapper;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.InputException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.ws.rs.*;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.sqlWrapper.QuerryAnd;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink;
import org.kar.archidata.util.JWTWrapper;
import org.kar.karso.model.Application;
import org.kar.karso.model.ApplicationSmall;
import org.kar.karso.model.RightDescription;
import org.kar.karso.model.UserAuth;
import org.kar.karso.model.UserLinkApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Path("/application")
@Produces( MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ApplicationResource {
final Logger logger = LoggerFactory.getLogger(ApplicationResource.class);
public ApplicationResource() {
}
public List<Long> getUserListOfApplication(Long userId) {
List<Long> out = new ArrayList<>();
public ApplicationResource() {}
public List<Long> getUserListOfApplication(final Long userId) {
final List<Long> out = new ArrayList<>();
List<UserLinkApplication> links = null;
try {
links = SqlWrapper.getsWhere(UserLinkApplication.class,
List.of(
new WhereCondition("user_id", "=", userId),
new WhereCondition("deleted", "=", 0)
), false);
} catch (Exception e) {
try {
links = SqlWrapper.getsWhere(UserLinkApplication.class, new QuerryAnd(new QuerryCondition("user_id", "=", userId), new QuerryCondition("deleted", "=", 0)), false);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
logger.error(" result: {}", result);
final String result = "SERVER Internal error";
this.logger.error(" result: {}", result);
return out;
}
for (UserLinkApplication app : links) {
out.add(app.application_id);
}
return out;
for (final UserLinkApplication app : links) {
out.add(app.application_id);
}
return out;
}
public List<Long> getListOfUsers(Long applicationId) {
List<Long> out = new ArrayList<>();
public List<Long> getListOfUsers(final Long applicationId) {
final List<Long> out = new ArrayList<>();
List<UserLinkApplication> links = null;
try {
links = SqlWrapper.getsWhere(UserLinkApplication.class,
List.of(
new WhereCondition("application_id", "=", applicationId),
new WhereCondition("deleted", "=", 0)
), false);
} catch (Exception e) {
try {
links = SqlWrapper.getsWhere(UserLinkApplication.class, new QuerryAnd(new QuerryCondition("application_id", "=", applicationId), new QuerryCondition("deleted", "=", 0)), false);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
logger.error(" result: {}", result);
final String result = "SERVER Internal error";
this.logger.error(" result: {}", result);
return out;
}
logger.debug("Find list of user for an application: {}", links);
for (UserLinkApplication app : links) {
out.add(app.user_id);
}
return out;
this.logger.debug("Find list of user for an application: {}", links);
for (final UserLinkApplication app : links) {
out.add(app.user_id);
}
return out;
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Generic /application/
//
////////////////////////////////////////////////////////////////////////////////////////
@GET
@RolesAllowed(value= {"USER", "ADMIN"})
public List<Application> getApplications(@Context SecurityContext sc) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.debug("getApplications");
@GET
@RolesAllowed(value = { "USER", "ADMIN" })
public List<Application> getApplications(@Context final SecurityContext sc) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("getApplications");
// TODO filter with the list of element available in his authorizations ...
List<Application> tmp = SqlWrapper.gets(Application.class, false);
final List<Application> tmp = SqlWrapper.gets(Application.class, false);
if (gc.userByToken.hasRight("ADMIN", true)) {
return tmp;
}
List<Long> regular = this.getUserListOfApplication(gc.userByToken.id);
List<Application> out = new ArrayList<>();
for (Application app : tmp) {
if (regular.indexOf(app.id) != -1) {
out.add(app);
}
}
final List<Long> regular = getUserListOfApplication(gc.userByToken.id);
final List<Application> out = new ArrayList<>();
for (final Application app : tmp) {
if (regular.indexOf(app.id) != -1) {
out.add(app);
}
}
return out;
}
@POST
@RolesAllowed("ADMIN")
public Application create(Application application) throws Exception {
logger.debug("create new application {}", application);
@RolesAllowed("ADMIN")
public Application create(final Application application) throws Exception {
this.logger.debug("create new application {}", application);
// verify login or email is correct:
if (application.name == null || application.name.length() < 5) {
throw new InputException("name", "create application (name too small: '" + application.name + "')");
@ -115,178 +121,171 @@ public class ApplicationResource {
application.modify_date = null;
return SqlWrapper.insert(application);
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Generic /application/{id}
//
////////////////////////////////////////////////////////////////////////////////////////
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public Application get(@PathParam("id") Long id) throws Exception {
return SqlWrapper.get(Application.class, id);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public Application get(@PathParam("id") final Long id) throws Exception {
return SqlWrapper.get(Application.class, id);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Application put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
SqlWrapper.update(Application.class, id, jsonRequest);
return SqlWrapper.get(Application.class, id);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Application put(@PathParam("id") Long id, String jsonRequest) throws Exception {
SqlWrapper.update(Application.class, id, jsonRequest);
return SqlWrapper.get(Application.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
@Produces( value = MediaType.TEXT_PLAIN )
public void remove(@Context SecurityContext sc, @PathParam("id") long applicationId) throws Exception {
@RolesAllowed("ADMIN")
@Produces(value = MediaType.TEXT_PLAIN)
public void remove(@Context final SecurityContext sc, @PathParam("id") final long applicationId) throws Exception {
SqlWrapper.setDelete(Application.class, applicationId);
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Generic /{id}/*
//
////////////////////////////////////////////////////////////////////////////////////////
@GET
@Path("{id}/users")
@RolesAllowed(value= {"ADMIN"})
public List<Long> getApplicationUsers(@PathParam("id") Long applicationId) throws Exception {
// special case for SSO: (all user have access on the SSO...).
logger.debug("Request list of user for an applciation: {}", applicationId);
@GET
@Path("{id}/users")
@RolesAllowed(value = { "ADMIN" })
public List<Long> getApplicationUsers(@PathParam("id") final Long applicationId) throws Exception {
// special case for SSO: (all user have access on the SSO...).
this.logger.debug("Request list of user for an applciation: {}", applicationId);
return getListOfUsers(applicationId);
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Generic /application/*
//
////////////////////////////////////////////////////////////////////////////////////////
@GET
@Path("small")
@RolesAllowed(value= {"USER", "ADMIN"})
public List<ApplicationSmall> getApplicationsSmall(@Context SecurityContext sc) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.debug("getApplications");
List<Application> tmp = SqlWrapper.gets(Application.class, false);
List<Long> regular = this.getUserListOfApplication(gc.userByToken.id);
List<ApplicationSmall> out = new ArrayList<>();
for (Application app : tmp) {
if (regular.indexOf(app.id) != -1) {
out.add(new ApplicationSmall(app.name, app.description, app.redirect));
}
}
@GET
@Path("small")
@RolesAllowed(value = { "USER", "ADMIN" })
public List<ApplicationSmall> getApplicationsSmall(@Context final SecurityContext sc) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("getApplications");
final List<Application> tmp = SqlWrapper.gets(Application.class, false);
final List<Long> regular = getUserListOfApplication(gc.userByToken.id);
final List<ApplicationSmall> out = new ArrayList<>();
for (final Application app : tmp) {
if (regular.indexOf(app.id) != -1) {
out.add(new ApplicationSmall(app.name, app.description, app.redirect));
}
}
return out;
}
public record AddUserData(long userId) {};
// TODO : review the function to correct admin only access...
@POST
@Path("{id}/users")
@RolesAllowed(value= {"ADMIN"})
public boolean addUser(@PathParam("id") Long applicationId, AddUserData data) throws Exception {
logger.debug("getApplications");
SqlWrapper.addLink(UserAuth.class, data.userId, "application", applicationId);
public record AddUserData(
long userId) {};
// TODO : review the function to correct admin only access...
@POST
@Path("{id}/users")
@RolesAllowed(value = { "ADMIN" })
public boolean addUser(@PathParam("id") final Long applicationId, final AddUserData data) throws Exception {
this.logger.debug("getApplications");
AddOnSQLTableExternalLink.addLink(UserAuth.class, data.userId, "application", applicationId);
return true;
}
// TODO : review the function to correct admin only access...
@DELETE
@Path("{id}/users")
@RolesAllowed(value= {"ADMIN"})
public boolean rmUser(@PathParam("id") Long applicationId, AddUserData data) throws Exception {
logger.debug("getApplications");
SqlWrapper.removeLink(UserAuth.class, data.userId, "application", applicationId);
// TODO : review the function to correct admin only access...
@DELETE
@Path("{id}/users")
@RolesAllowed(value = { "ADMIN" })
public boolean rmUser(@PathParam("id") final Long applicationId, final AddUserData data) throws Exception {
this.logger.debug("getApplications");
AddOnSQLTableExternalLink.removeLink(UserAuth.class, data.userId, "application", applicationId);
return true;
}
// TODO : review the function to correct admin only access...
@GET
@Path("{id}/rights")
@RolesAllowed(value= {"ADMIN"})
public List<RightDescription> getRightsDescription(@PathParam("id") Long applicationId) throws Exception {
logger.debug("getApplications rights");
return SqlWrapper.getsWhere(RightDescription.class, List.of(
new WhereCondition("applicationId", "=", applicationId)),
false);
// TODO : review the function to correct admin only access...
@GET
@Path("{id}/rights")
@RolesAllowed(value = { "ADMIN" })
public List<RightDescription> getRightsDescription(@PathParam("id") final Long applicationId) throws Exception {
this.logger.debug("getApplications rights");
return SqlWrapper.getsWhere(RightDescription.class, new QuerryCondition("applicationId", "=", applicationId), false);
}
@GET
@Path("get_token")
@RolesAllowed(value= {"USER", "ADMIN"})
public Response getClientToken(@Context SecurityContext sc, @QueryParam("application") String application) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.info("get application TOKEN application name='{}'", application);
logger.debug("== USER ? {}", gc.userByToken.name);
@GET
@Path("get_token")
@RolesAllowed(value = { "USER", "ADMIN" })
public Response getClientToken(@Context final SecurityContext sc, @QueryParam("application") final String application) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.info("get application TOKEN application name='{}'", application);
this.logger.debug("== USER ? {}", gc.userByToken.name);
if (application == null) {
String result = "Input error missing parameter: 'application'";
logger.debug(" result: {}", result);
final String result = "Input error missing parameter: 'application'";
this.logger.debug(" result: {}", result);
return Response.status(406).entity(result).build();
}
String applicationName = application;
boolean isDev = false;
if (applicationName.endsWith("-dev")) {
applicationName = applicationName.substring(0, applicationName.length()-4);
isDev = true;
}
logger.debug("Search for '{}' base of '{}'", applicationName, application);
String applicationName = application;
boolean isDev = false;
if (applicationName.endsWith("-dev")) {
applicationName = applicationName.substring(0, applicationName.length() - 4);
isDev = true;
}
this.logger.debug("Search for '{}' base of '{}'", applicationName, application);
Application appl = null;
try {
appl = SqlWrapper.getWhere(Application.class, List.of(new WhereCondition("name", "=", applicationName)), false);
} catch (Exception e) {
try {
appl = SqlWrapper.getWhere(Application.class, new QuerryCondition("name", "=", applicationName), false);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
logger.debug(" result: {}", result);
final String result = "SERVER Internal error";
this.logger.debug(" result: {}", result);
return Response.status(500).entity(result).build();
}
if (appl == null) {
String result = "Authentiocate-wrong email/login '" + applicationName + "')";
logger.error(" result: {}", result);
final String result = "Authentiocate-wrong email/login '" + applicationName + "')";
this.logger.error(" result: {}", result);
return Response.status(401).entity(result).build();
}
UserLinkApplication links = null;
try {
links = SqlWrapper.getWhere(UserLinkApplication.class,
List.of(
new WhereCondition("user_id", "=", gc.userByToken.id),
new WhereCondition("deleted", "=", 0),
new WhereCondition("application_id", "=", appl.id)
), false);
} catch (Exception e) {
try {
links = SqlWrapper.getWhere(UserLinkApplication.class,
new QuerryAnd(new QuerryCondition("user_id", "=", gc.userByToken.id), new QuerryCondition("deleted", "=", 0), new QuerryCondition("application_id", "=", appl.id)), false);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
logger.error(" result: {}", result);
final String result = "SERVER Internal error";
this.logger.error(" result: {}", result);
return Response.status(500).entity(result).build();
}
if (links == null) {
String result = "Authenticate impossible ==> application not accessible '" + applicationName + "'";
logger.error(" result: {}", result);
final String result = "Authenticate impossible ==> application not accessible '" + applicationName + "'";
this.logger.error(" result: {}", result);
return Response.status(401).entity(result).build();
}
// Get the USER Right
Map<String, Object> applicationRight = RightResource.getUserRight(gc.userByToken.id, appl.id);
final Map<String, Object> applicationRight = RightResource.getUserRight(gc.userByToken.id, appl.id);
if (!applicationRight.containsKey("USER")) {
// If the USER is not override, the system add by default USER
applicationRight.put("USER", true);
}
Map<String, Object> outRight = new HashMap<>();
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(applicationName, applicationRight);
String ret = JWTWrapper.generateJWToken(gc.userByToken.id, gc.userByToken.name, "KarAuth", applicationName, outRight, -appl.ttl);
final String ret = JWTWrapper.generateJWToken(gc.userByToken.id, gc.userByToken.name, "KarAuth", applicationName, outRight, -appl.ttl);
//logger.debug(" ==> generate token: {}", ret);
String returnAdress = appl.redirect;
if (isDev) {
@ -294,44 +293,44 @@ public class ApplicationResource {
}
return Response.status(201).entity("{ \"url\":\"" + returnAdress + "\", \"jwt\":\"" + ret + "\"}").build();
}
@GET
@Path("return")
@RolesAllowed(value= {"USER", "ADMIN"})
public Response logOut(@Context SecurityContext sc, @QueryParam("application") String application) {
logger.debug("=====================================");
logger.debug("Get log_out()");
logger.debug("=====================================");
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.debug("== USER ? {}", gc.userByToken);
@GET
@Path("return")
@RolesAllowed(value = { "USER", "ADMIN" })
public Response logOut(@Context final SecurityContext sc, @QueryParam("application") final String application) {
this.logger.debug("=====================================");
this.logger.debug("Get log_out()");
this.logger.debug("=====================================");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("== USER ? {}", gc.userByToken);
if (application == null) {
String result = "Input error missing parameter: 'application'";
logger.error(" result: {}", result);
final String result = "Input error missing parameter: 'application'";
this.logger.error(" result: {}", result);
return Response.status(406).entity(result).build();
}
String applicationName = application;
boolean isDev = false;
if (applicationName.endsWith("-dev")) {
applicationName = applicationName.substring(0, applicationName.length()-4);
isDev = true;
}
logger.debug("Search for '{}' base of '{}'", applicationName, application);
String applicationName = application;
boolean isDev = false;
if (applicationName.endsWith("-dev")) {
applicationName = applicationName.substring(0, applicationName.length() - 4);
isDev = true;
}
this.logger.debug("Search for '{}' base of '{}'", applicationName, application);
Application appl = null;
try {
appl = SqlWrapper.getWhere(Application.class, "name", "=", applicationName);
} catch (Exception e) {
try {
appl = SqlWrapper.getWhere(Application.class, new QuerryCondition("name", "=", applicationName));
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "SERVER Internal error";
logger.error(" result: {}", result);
final String result = "SERVER Internal error";
this.logger.error(" result: {}", result);
return Response.status(500).entity(result).build();
}
if (appl == null) {
String result = "Authentiocate-wrong email/login '" + applicationName + "')";
logger.error(" result: {}", result);
final String result = "Authentiocate-wrong email/login '" + applicationName + "')";
this.logger.error(" result: {}", result);
return Response.status(404).entity(result).build();
}
String returnAdress = appl.redirect;
@ -341,37 +340,4 @@ public class ApplicationResource {
return Response.status(201).entity("{ \"url\":\"" + returnAdress + "\"}").build();
}
}

View File

@ -1,178 +1,137 @@
package org.kar.karso.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.karso.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.InputException;
import java.sql.Timestamp;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.List;
import jakarta.ws.rs.*;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.InputException;
import org.kar.archidata.sqlWrapper.QuerryAnd;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.karso.model.ApplicationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Path("/application_token")
@Produces( MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class ApplicationTokenResource {
final Logger logger = LoggerFactory.getLogger(ApplicationTokenResource.class);
public ApplicationTokenResource() {
}
public ApplicationTokenResource() {}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
//
// Generic /application_token/{applicationId}
//
////////////////////////////////////////////////////////////////////////////////////////
@GET
@Path("{applicationId}")
@RolesAllowed(value= {"ADMIN"})
public List<ApplicationToken> gets(@Context SecurityContext sc, @PathParam("applicationId") Long applicationId) throws Exception {
List<ApplicationToken> values = SqlWrapper.getsWhere(ApplicationToken.class,
List.of(
new WhereCondition("parentId", "=", applicationId)
),
false);
// clean all tokens this is a secret:
for (ApplicationToken elem : values) {
elem.token = null;
}
return values;
@GET
@Path("{applicationId}")
@RolesAllowed(value = { "ADMIN" })
public List<ApplicationToken> gets(@Context final SecurityContext sc, @PathParam("applicationId") final Long applicationId) throws Exception {
final List<ApplicationToken> values = SqlWrapper.getsWhere(ApplicationToken.class, new QuerryCondition("parentId", "=", applicationId), false);
// clean all tokens this is a secret:
for (final ApplicationToken elem : values) {
elem.token = null;
}
return values;
}
@DELETE
@Path("{applicationId}/{tokenId}")
@RolesAllowed(value= {"ADMIN"})
public Response delete(
@Context SecurityContext sc,
@PathParam("applicationId") Long applicationId,
@PathParam("tokenId") Integer tokenId) throws Exception {
int nbRemoved = SqlWrapper.setDeleteWhere(ApplicationToken.class,
List.of(
new WhereCondition("parentId", "=", applicationId),
new WhereCondition("id", "=", tokenId)
)
);
@DELETE
@Path("{applicationId}/{tokenId}")
@RolesAllowed(value = { "ADMIN" })
public Response delete(@Context final SecurityContext sc, @PathParam("applicationId") final Long applicationId, @PathParam("tokenId") final Integer tokenId) throws Exception {
final int nbRemoved = SqlWrapper.setDeleteWhere(ApplicationToken.class, new QuerryAnd(new QuerryCondition("parentId", "=", applicationId), new QuerryCondition("id", "=", tokenId)));
if (nbRemoved == 0) {
return Response.notModified("{}").build();
}
if (nbRemoved == 0) {
return Response.serverError().build();
}
return Response.ok("{}").build();
return Response.ok("{}").build();
}
private String multipartCorrection(String data) {
if (data == null) {
return null;
}
if (data.isEmpty()) {
return null;
}
if (data.contentEquals("null")) {
return null;
}
return data;
}
static String randomToken() {
int len = 48;
String valid_element = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz0123456789#_@-~*!?";
// creating a StringBuffer size of AlphaNumericStr
StringBuilder out = new StringBuilder(len);
int iii;
for (iii=0; iii<len; iii++) {
//generating a random number using math.random()
int ch = (int)(valid_element.length() * Math.random());
//adding Random character one by one at the end of s
out.append(valid_element.charAt(ch));
}
return out.toString();
}
public record CreateRequest(String name, Integer validity) {};
@POST
@Path("/{applicationId}/create")
@RolesAllowed("ADMIN")
public ApplicationToken createToken(
@Context SecurityContext sc,
@PathParam("applicationId") Long applicationId,
CreateRequest request
) throws Exception {
logger.info("get user application TOKEN: app='{}' user='???'", applicationId);
// correct input string stream :
String name = multipartCorrection(request.name());
//validity = multipartCorrection(validity);
logger.debug("create a new token...");
if (applicationId == null) {
throw new InputException("applicationId", "can not be null");
}
int maximum = 365*5;
Integer validity = request.validity();
if (validity == null || validity < 0 || validity > maximum) {
validity = maximum;
}
logger.warn("validity= {}", validity);
// todo: set validity timestamp ...
// TODO: check if application exist ...
ApplicationToken token = new ApplicationToken();
token.token = randomToken();
token.name = multipartCorrection(name);
token.parentId = applicationId;
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
logger.warn("Check Timestamp now = {}", now);
token.endValidityTime = Timestamp.from(now.plusDays(validity).toInstant());
logger.warn("token.endValidityTime = {}", token.endValidityTime);
// insert in the BDD
token = SqlWrapper.insert(token);
// here we return the token to permit to the user to see it to set it in the application.
return token;
}
/*
Cannot find a deserializer for non-concrete Map type [map type; class jakarta.ws.rs.core.MultivaluedMap, [simple type, class java.lang.String] -> [collection type; class java.util.List, contains [simple type, class java.lang.String]]]
at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 1]
*/
private String multipartCorrection(final String data) {
if (data == null) {
return null;
}
if (data.isEmpty()) {
return null;
}
if (data.contentEquals("null")) {
return null;
}
return data;
}
static String randomToken() {
final int len = 48;
final String valid_element = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz0123456789#_@-~*!?";
// creating a StringBuffer size of AlphaNumericStr
final StringBuilder out = new StringBuilder(len);
int iii;
for (iii = 0; iii < len; iii++) {
//generating a random number using math.random()
final int ch = (int) (valid_element.length() * Math.random());
//adding Random character one by one at the end of s
out.append(valid_element.charAt(ch));
}
return out.toString();
}
public record CreateRequest(
String name,
Integer validity) {};
@POST
@Path("/{applicationId}/create")
@RolesAllowed("ADMIN")
public ApplicationToken createToken(@Context final SecurityContext sc, @PathParam("applicationId") final Long applicationId, final CreateRequest request) throws Exception {
this.logger.info("get user application TOKEN: app='{}' user='???'", applicationId);
// correct input string stream :
final String name = multipartCorrection(request.name());
//validity = multipartCorrection(validity);
this.logger.debug("create a new token...");
if (applicationId == null) {
throw new InputException("applicationId", "can not be null");
}
final int maximum = 365 * 5;
Integer validity = request.validity();
if (validity == null || validity < 0 || validity > maximum) {
validity = maximum;
}
this.logger.warn("validity= {}", validity);
// todo: set validity timestamp ...
// TODO: check if application exist ...
ApplicationToken token = new ApplicationToken();
token.token = randomToken();
token.name = multipartCorrection(name);
token.parentId = applicationId;
final OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
this.logger.warn("Check Timestamp now = {}", now);
token.endValidityTime = Timestamp.from(now.plusDays(validity).toInstant());
this.logger.warn("token.endValidityTime = {}", token.endValidityTime);
// insert in the BDD
token = SqlWrapper.insert(token);
// here we return the token to permit to the user to see it to set it in the application.
return token;
}
/*
Cannot find a deserializer for non-concrete Map type [map type; class jakarta.ws.rs.core.MultivaluedMap, [simple type, class java.lang.String] -> [collection type; class java.util.List, contains [simple type, class java.lang.String]]]
at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 1]
*/
}

View File

@ -1,66 +1,60 @@
package org.kar.karso.api;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import org.kar.karso.model.Right;
import org.kar.karso.model.RightDescription;
import org.kar.karso.util.Transform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLForeignKey;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.security.RolesAllowed;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.sqlWrapper.QuerryAnd;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.karso.model.Right;
import org.kar.karso.model.RightDescription;
import org.kar.karso.util.Transform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/right")
@Produces({MediaType.APPLICATION_JSON})
@Produces({ MediaType.APPLICATION_JSON })
public class RightResource {
final static Logger logger = LoggerFactory.getLogger(RightResource.class);
public static List<RightDescription> getApplicationRightDecription(long applicationId) throws Exception {
return SqlWrapper.getsWhere(RightDescription.class,
List.of(
new WhereCondition("applicationId", "=", applicationId),
new WhereCondition("deleted", "=", 0)
));
public static List<RightDescription> getApplicationRightDecription(final long applicationId) throws Exception {
return SqlWrapper.getsWhere(RightDescription.class, new QuerryAnd(new QuerryCondition("applicationId", "=", applicationId), new QuerryCondition("deleted", "=", 0)));
}
public static List<Right> getRawUserRight(long userId, long applicationId) throws Exception {
public static List<Right> getRawUserRight(final long userId, final long applicationId) throws Exception {
return SqlWrapper.getsWhere(Right.class,
List.of(
new WhereCondition("applicationId", "=", applicationId),
new WhereCondition("userId", "=", userId),
new WhereCondition("deleted", "=", 0)
));
new QuerryAnd(new QuerryCondition("applicationId", "=", applicationId), new QuerryCondition("userId", "=", userId), new QuerryCondition("deleted", "=", 0)));
}
public static Map<String, Object> getUserRight(long userId, long applicationId) throws Exception {
Map<String, Object> out = new HashMap<>();
List<RightDescription> rightsDescriptions = getApplicationRightDecription(applicationId);
public static Map<String, Object> getUserRight(final long userId, final long applicationId) throws Exception {
final Map<String, Object> out = new HashMap<>();
final List<RightDescription> rightsDescriptions = getApplicationRightDecription(applicationId);
logger.debug("Get some descriptions: {} applicationId={}", rightsDescriptions.size(), applicationId);
if (rightsDescriptions != null && rightsDescriptions.size() != 0) {
List<Right> rights = getRawUserRight(userId, applicationId);
final List<Right> rights = getRawUserRight(userId, applicationId);
logger.debug("Get some user right: {}userID={}", rights.size(), userId);
for (RightDescription description : rightsDescriptions) {
for (final RightDescription description : rightsDescriptions) {
if (description == null) {
// TODO: this is a really strange case to manage later...
continue;
}
Right right = rights.stream()
.filter(elem -> elem.rightDescriptionId == description.id)
.findAny()
.orElse(null);
final Right right = rights.stream().filter(elem -> elem.rightDescriptionId == description.id).findAny().orElse(null);
if (right != null) {
out.put(description.key, Transform.convertToType(description.type, right.value));
} else if (description.defaultValue != null){
} else if (description.defaultValue != null) {
out.put(description.key, Transform.convertToType(description.type, description.defaultValue));
} else {
out.put(description.key, null);
@ -71,39 +65,37 @@ public class RightResource {
logger.debug("Does not manage Karso right...");
}
return out;
}
public static void updateUserRight(long userId, long applicationId, Map<String, Object> delta) throws Exception {
List<RightDescription> rightsDescriptions = getApplicationRightDecription(applicationId);
}
public static void updateUserRight(final long userId, final long applicationId, final Map<String, Object> delta) throws Exception {
final List<RightDescription> rightsDescriptions = getApplicationRightDecription(applicationId);
logger.debug("Get some descriptions: {} applicationId={}", rightsDescriptions.size(), applicationId);
if (rightsDescriptions == null || rightsDescriptions.size() == 0) {
throw new IllegalArgumentException("Request change right on an application that does not manage any right");
}
List<Right> rights = getRawUserRight(userId, applicationId);
final List<Right> rights = getRawUserRight(userId, applicationId);
logger.debug("Get some user right: {}userID={}", rights.size(), userId);
for (RightDescription description : rightsDescriptions) {
for (final RightDescription description : rightsDescriptions) {
if (description == null) {
// TODO: this is a really strange case to manage later...
continue;
}
Object newValue = delta.get(description.key);
final Object newValue = delta.get(description.key);
if (newValue == null) {
//No need to update or create...
continue;
}
String convertedValue = Transform.convertToStringCheck(description.type, newValue);
final String convertedValue = Transform.convertToStringCheck(description.type, newValue);
if (convertedValue == null) {
throw new IllegalArgumentException("Uncompatible value:'" + description.type + "'");
}
Right right = rights.stream()
.filter(elem -> elem.rightDescriptionId == description.id)
.findAny()
.orElse(null);
Right right = rights.stream().filter(elem -> elem.rightDescriptionId == description.id).findAny().orElse(null);
if (right != null) {
// The value exist, we need to update it
logger.debug("Request update a knonwn parameter: {} with {}", description.key, newValue);
right.value = convertedValue;
SqlWrapper.update(right, right.id, List.of("value"));
} else {
} else {
// we need to create it
logger.debug("Request create parameter: {} with {}", description.key, newValue);
right = new Right();
@ -114,45 +106,43 @@ public class RightResource {
SqlWrapper.insert(right);
}
}
}
@GET
@RolesAllowed("ADMIN")
public List<Right> get() throws Exception {
return SqlWrapper.gets(Right.class, false);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Right post(String jsonRequest) throws Exception {
return SqlWrapper.insertWithJson(Right.class, jsonRequest);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public static Right getWithId(@PathParam("id") Long id) throws Exception {
return SqlWrapper.get(Right.class, id);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Right put(@PathParam("id") Long id, String jsonRequest) throws Exception {
SqlWrapper.update(Right.class, id, jsonRequest);
return SqlWrapper.get(Right.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") Long id) throws Exception {
SqlWrapper.setDelete(Right.class, id);
return Response.ok().build();
}
}
@GET
@RolesAllowed("ADMIN")
public List<Right> get() throws Exception {
return SqlWrapper.gets(Right.class, false);
}
@POST
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Right post(final String jsonRequest) throws Exception {
return SqlWrapper.insertWithJson(Right.class, jsonRequest);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public static Right getWithId(@PathParam("id") final Long id) throws Exception {
return SqlWrapper.get(Right.class, id);
}
@PUT
@Path("{id}")
@RolesAllowed("ADMIN")
@Consumes(MediaType.APPLICATION_JSON)
public Right put(@PathParam("id") final Long id, final String jsonRequest) throws Exception {
SqlWrapper.update(Right.class, id, jsonRequest);
return SqlWrapper.get(Right.class, id);
}
@DELETE
@Path("{id}")
@RolesAllowed("ADMIN")
public Response delete(@PathParam("id") final Long id) throws Exception {
SqlWrapper.setDelete(Right.class, id);
return Response.ok().build();
}
}

View File

@ -1,101 +1,106 @@
package org.kar.karso.api;
import org.kar.archidata.SqlWrapper;
import org.kar.karso.model.*;
import java.util.List;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.NotFoundException;
import org.kar.archidata.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.karso.model.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.exception.NotFoundException;
import java.util.List;
import jakarta.ws.rs.*;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
@Path("/system_config")
@Produces( MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class SystemConfigResource {
final Logger logger = LoggerFactory.getLogger(SystemConfigResource.class);
public static class GetSignUpAvaillable {
public boolean signup;
public GetSignUpAvaillable(boolean availlable) {
public GetSignUpAvaillable(final boolean availlable) {
this.signup = availlable;
}
public GetSignUpAvaillable() {
signup = false;
this.signup = false;
}
}
public SystemConfigResource() {
}
public SystemConfigResource() {}
@GET
@Path("is_sign_up_availlable")
@PermitAll
public GetSignUpAvaillable isSignUpAvaillable() throws Exception {
Settings set = SqlWrapper.getWhere(Settings.class, "key", "=", "SIGN_UP_ENABLE", false);
if (set == null) {
throw new NotFoundException("Value does not exist");
@GET
@Path("is_sign_up_availlable")
@PermitAll
public GetSignUpAvaillable isSignUpAvaillable() throws Exception {
final Settings set = SqlWrapper.getWhere(Settings.class, new QuerryCondition("key", "=", "SIGN_UP_ENABLE"), false);
if (set == null) {
throw new NotFoundException("Value does not exist");
}
boolean availlable = "true".equalsIgnoreCase(set.value);
GetSignUpAvaillable tmp = new GetSignUpAvaillable(availlable);
logger.debug("mlkmlk {}", tmp.signup);
final boolean availlable = "true".equalsIgnoreCase(set.value);
final GetSignUpAvaillable tmp = new GetSignUpAvaillable(availlable);
this.logger.debug("mlkmlk {}", tmp.signup);
return tmp;
}
@GET
@Path("key/{key}")
@RolesAllowed(value= {"USER", "ADMIN"})
public Response getKey(@Context SecurityContext sc, @PathParam("key") String key) throws Exception {
Settings set = SqlWrapper.getWhere(Settings.class, "key", "=", key, false);
if (set == null) {
throw new NotFoundException("Value does not exist");
@GET
@Path("key/{key}")
@RolesAllowed(value = { "USER", "ADMIN" })
public Response getKey(@Context final SecurityContext sc, @PathParam("key") final String key) throws Exception {
final Settings set = SqlWrapper.getWhere(Settings.class, new QuerryCondition("key", "=", key), false);
if (set == null) {
throw new NotFoundException("Value does not exist");
}
if (set.type.equals("BOOLEAN")) {
boolean availlable = "true".equalsIgnoreCase(set.value);
return Response.status(200).entity("{ \"value\":" + availlable + "}").build();
}
if (set.type.equals("NUMBER")) {
double value = Double.parseDouble(set.value);
return Response.status(200).entity("{ \"value\":" + value + "}").build();
}
return Response.status(200).entity("{ \"value\":\"" + set.value + "\"}").build();
if (set.type.equals("BOOLEAN")) {
final boolean availlable = "true".equalsIgnoreCase(set.value);
return Response.status(200).entity("{ \"value\":" + availlable + "}").build();
}
if (set.type.equals("NUMBER")) {
final double value = Double.parseDouble(set.value);
return Response.status(200).entity("{ \"value\":" + value + "}").build();
}
return Response.status(200).entity("{ \"value\":\"" + set.value + "\"}").build();
}
@PUT
@Path("key/{key}")
@RolesAllowed(value= {"ADMIN"})
@Consumes(MediaType.APPLICATION_JSON)
public Response setKey(@Context SecurityContext sc, @PathParam("key") String key, String jsonRequest) throws Exception {
Settings res = null;
try {
res = SqlWrapper.getWhere(Settings.class, "key", "=", key, false);
} catch (Exception e) {
@PUT
@Path("key/{key}")
@RolesAllowed(value = { "ADMIN" })
@Consumes(MediaType.APPLICATION_JSON)
public Response setKey(@Context final SecurityContext sc, @PathParam("key") final String key, final String jsonRequest) throws Exception {
Settings res = null;
try {
res = SqlWrapper.getWhere(Settings.class, new QuerryCondition("key", "=", key), false);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String result = "Can not find the Key";
final String result = "Can not find the Key";
return Response.status(404).entity(result).build();
}
ObjectMapper mapper = new ObjectMapper();
// Read the tree to filter injection of data:
JsonNode root = mapper.readTree(jsonRequest);
JsonNode value = root.findPath("value");
res.value = value.asText();
logger.debug("Update value : {}", res.value);
SqlWrapper.update(res, res.id, List.of("value"));
return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build();
final ObjectMapper mapper = new ObjectMapper();
// Read the tree to filter injection of data:
final JsonNode root = mapper.readTree(jsonRequest);
final JsonNode value = root.findPath("value");
res.value = value.asText();
this.logger.debug("Update value : {}", res.value);
SqlWrapper.update(res, res.id, List.of("value"));
return Response.status(201).entity("{ \"value\":\"" + res.value + "\"}").build();
}
}

View File

@ -1,41 +1,53 @@
package org.kar.karso.api;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.WhereCondition;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.RolesAllowed;
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.sqlWrapper.QuerryCondition;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.archidata.sqlWrapper.addOn.AddOnSQLTableExternalLink;
import org.kar.archidata.util.JWTWrapper;
import org.kar.karso.migration.Initialization;
import org.kar.karso.model.*;
import org.kar.karso.model.ChangePassword;
import org.kar.karso.model.DataGetToken;
import org.kar.karso.model.UserAuth;
import org.kar.karso.model.UserAuthGet;
import org.kar.karso.model.UserCreate;
import org.kar.karso.util.ConfigVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.kar.archidata.util.JWTWrapper;
import jakarta.ws.rs.*;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.SecurityContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
@Path("/users")
@Produces( MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserResource {
final Logger logger = LoggerFactory.getLogger(UserResource.class);
@ -43,98 +55,93 @@ public class UserResource {
public class UserOut {
public long id;
public String login;
public UserOut(long id, String login) {
super();
public UserOut(final long id, final String login) {
this.id = id;
this.login = login;
}
}
public UserResource() {
}
public UserResource() {}
@GET
@RolesAllowed("ADMIN")
@RolesAllowed("ADMIN")
public List<UserAuthGet> getUsers() throws Exception {
return SqlWrapper.gets(UserAuthGet.class, false);
}
@GET
@Path("{id}")
@RolesAllowed("ADMIN")
public UserAuthGet getUser(@Context SecurityContext sc, @PathParam("id") long userId) throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
return SqlWrapper.get(UserAuthGet.class, userId);
@RolesAllowed("ADMIN")
public UserAuthGet getUser(@Context final SecurityContext sc, @PathParam("id") final long userId) throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
return SqlWrapper.get(UserAuthGet.class, userId);
}
@POST
@Path("{userId}/application/{applicationId}/link")
@RolesAllowed("ADMIN")
public UserAuth linkApplication(@Context SecurityContext sc,
@PathParam("userId") long userId,
@PathParam("applicationId") long applicationId,
boolean data) throws Exception {
logger.debug("Find typeNode");
if (data == true) {
SqlWrapper.addLink(UserAuth.class, userId, "application", applicationId);
} else {
SqlWrapper.removeLink(UserAuth.class, userId, "application", applicationId);
}
return SqlWrapper.get(UserAuth.class, userId);
@RolesAllowed("ADMIN")
public UserAuth linkApplication(@Context final SecurityContext sc, @PathParam("userId") final long userId, @PathParam("applicationId") final long applicationId, final boolean data)
throws Exception {
this.logger.debug("Find typeNode");
if (data) {
AddOnSQLTableExternalLink.addLink(UserAuth.class, userId, "application", applicationId);
} else {
AddOnSQLTableExternalLink.removeLink(UserAuth.class, userId, "application", applicationId);
}
return SqlWrapper.get(UserAuth.class, userId);
}
@GET
@Path("{userId}/application/{applicationId}/rights")
@RolesAllowed("ADMIN")
public Map<String, Object> getApplicationRight(@Context SecurityContext sc,
@PathParam("userId") long userId,
@PathParam("applicationId") long applicationId) throws Exception {
@RolesAllowed("ADMIN")
public Map<String, Object> getApplicationRight(@Context final SecurityContext sc, @PathParam("userId") final long userId, @PathParam("applicationId") final long applicationId) throws Exception {
return RightResource.getUserRight(userId, applicationId);
}
@PUT
@Path("{userId}/application/{applicationId}/rights")
@RolesAllowed("ADMIN")
public Map<String, Object> patchApplicationRight(@Context SecurityContext sc,
@PathParam("userId") long userId,
@PathParam("applicationId") long applicationId, Map<String, Object> data) throws Exception {
logger.info("get data from FRONT: {}", data);
@RolesAllowed("ADMIN")
public Map<String, Object> patchApplicationRight(@Context final SecurityContext sc, @PathParam("userId") final long userId, @PathParam("applicationId") final long applicationId,
final Map<String, Object> data) throws Exception {
this.logger.info("get data from FRONT: {}", data);
RightResource.updateUserRight(userId, applicationId, data);
return RightResource.getUserRight(userId, applicationId);
}
// TODO: check this it might be deprecated ...
// TODO: check this it might be deprecated ...
@POST
@Path("{id}/set_admin")
@RolesAllowed("ADMIN")
public Response setAdmin(@Context SecurityContext sc, @PathParam("id") long userId, boolean data) throws Exception {
UserAuth user = new UserAuth();
@RolesAllowed("ADMIN")
public Response setAdmin(@Context final SecurityContext sc, @PathParam("id") final long userId, final boolean data) throws Exception {
final UserAuth user = new UserAuth();
user.admin = data;
int ret = SqlWrapper.update(user, userId, List.of("admin"));
final int ret = SqlWrapper.update(user, userId, List.of("admin"));
if (ret == 0) {
return Response.notModified("{}").build();
return Response.notModified("{}").build();
}
return Response.ok("{}").build();
return Response.ok("{}").build();
}
@POST
@Path("{id}/set_blocked")
@RolesAllowed("ADMIN")
public Response setBlocked(@Context SecurityContext sc, @PathParam("id") long userId, boolean data) throws Exception {
UserAuth user = new UserAuth();
@RolesAllowed("ADMIN")
public Response setBlocked(@Context final SecurityContext sc, @PathParam("id") final long userId, final boolean data) throws Exception {
final UserAuth user = new UserAuth();
user.blocked = data;
int ret = SqlWrapper.update(user, userId, List.of("blocked"));
final int ret = SqlWrapper.update(user, userId, List.of("blocked"));
if (ret == 0) {
return Response.notModified("{}").build();
}
return Response.ok("{}").build();
return Response.ok("{}").build();
}
@POST
@Path("create_new_user")
@RolesAllowed("ADMIN")
public UserAuthGet createUser(UserCreate user) throws Exception {
logger.debug("create new User email={} login={}", user.email, user.login);
@RolesAllowed("ADMIN")
public UserAuthGet createUser(final UserCreate user) throws Exception {
this.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 + "')");
@ -145,30 +152,25 @@ public class UserResource {
throw new InputException("email", "Authentiocate-method-error (email too small: '" + user.email + "')");
}
// TODO: check email format
if(user.password == null || user.password.length() != 128) {
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 ...
}
// TODO: verify if the data are a hash ...
// Check login does not exist
List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, List.of(
new WhereCondition("login", "=", user.login)
), false);
List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, new QuerryCondition("login", "=", user.login), false);
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "Login already used !!!");
}
// Check email does not exist
out = SqlWrapper.getsWhere(UserAuth.class, List.of(
new WhereCondition("email", "=", user.email)
), false);
out = SqlWrapper.getsWhere(UserAuth.class, new QuerryCondition("email", "=", user.email), false);
if (out.size() >= 1) {
throw new FailException(Response.Status.BAD_REQUEST, "e-mail already used !!!");
}
// Add new user and return formated dat.
UserAuth newUser = new UserAuth();
final UserAuth newUser = new UserAuth();
newUser.admin = false;
newUser.removed = false;
newUser.blocked = false;
@ -177,70 +179,68 @@ public class UserResource {
newUser.password = user.password;
newUser.email = user.email;
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
UserAuth tmp = SqlWrapper.insert(newUser);
logger.debug("create new user done with id=={}", tmp.id);
return SqlWrapper.get(UserAuthGet.class, tmp.id);
final UserAuth tmp = SqlWrapper.insert(newUser);
this.logger.debug("create new user done with id=={}", tmp.id);
return SqlWrapper.get(UserAuthGet.class, tmp.id);
}
@GET
@Path("me")
@RolesAllowed("USER")
public UserOut getMe(@Context SecurityContext sc) {
logger.debug("getMe()");
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.debug("== USER ? {}", gc.userByToken);
return new UserOut(gc.userByToken.id, gc.userByToken.name);
}
@GET
@Path("me")
@RolesAllowed("USER")
public UserOut getMe(@Context final SecurityContext sc) {
this.logger.debug("getMe()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("== USER ? {}", gc.userByToken);
return new UserOut(gc.userByToken.id, gc.userByToken.name);
}
@POST
@Path("password")
@RolesAllowed("USER")
public Response changePassword(@Context SecurityContext sc, ChangePassword data) throws Exception {
logger.debug("ChangePassword()");
GenericContext gc = (GenericContext) sc.getUserPrincipal();
logger.debug("== USER ? {}", gc.userByToken);
if(data == null) {
@POST
@Path("password")
@RolesAllowed("USER")
public Response changePassword(@Context final SecurityContext sc, final ChangePassword data) throws Exception {
this.logger.debug("ChangePassword()");
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
this.logger.debug("== USER ? {}", gc.userByToken);
if (data == null) {
throw new InputException("data", "No data set...");
}
if(data.newPassword == null || data.newPassword.length() != 128) {
}
if (data.newPassword == null || data.newPassword.length() != 128) {
throw new InputException("newPassword", "null password, or wrong hash size");
}
UserAuth user = checkAuthUser(data.method, data.login, data.time, data.password);
if (user == null) {
}
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;
SqlWrapper.update(user, user.id, List.of("password"));
return Response.status(Response.Status.OK).build();
}
/*
@GET
@Path("validipass")
@PermitAll
public Response validatePasswordFromEMail(@QueryParam("uuid") String uuid, @QueryParam("securityId") String securityId) {
// Validate new password if OK
// clear the passwordChange, passwordValidation fields
// send an e-mail to confirm the new password has been set.
// Process the update:
user.password = data.newPassword;
SqlWrapper.update(user, user.id, List.of("password"));
return Response.status(Response.Status.OK).build();
}
/*
@GET
@Path("validipass")
@PermitAll
public Response validatePasswordFromEMail(@QueryParam("uuid") String uuid, @QueryParam("securityId") String securityId) {
// Validate new password if OK
// clear the passwordChange, passwordValidation fields
// send an e-mail to confirm the new password has been set.
return Response.status(500).build();
}
*/
}
*/
@GET
@Path("/check_login")
@PermitAll
public Response checkLogin(@QueryParam("login") String login) throws Exception {
logger.debug("checkLogin: '{}'", login );
List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, List.of(
new WhereCondition("login", "=", login)
), false);
@PermitAll
public Response checkLogin(@QueryParam("login") final String login) throws Exception {
this.logger.debug("checkLogin: '{}'", login);
final List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, new QuerryCondition("login", "=", login), false);
if (out.size() >= 1) {
return Response.ok().build();
}
@ -250,20 +250,17 @@ public class UserResource {
// TODO: add an application TOKEN and permit only 50 requested (maybe add an option to disable it).
@GET
@Path("/check_email")
@PermitAll
public Response checkEmail(@QueryParam("email") String email) throws Exception {
logger.debug("checkEmail: {}", email );
List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, List.of(
new WhereCondition("email", "=", email)
), false);
@PermitAll
public Response checkEmail(@QueryParam("email") final String email) throws Exception {
this.logger.debug("checkEmail: {}", email);
final List<UserAuth> out = SqlWrapper.getsWhere(UserAuth.class, new QuerryCondition("email", "=", email), false);
if (out.size() >= 1) {
return Response.ok().build();
}
throw new NotFoundException("emain does not exist: '" + email + "'");
}
private UserAuth checkAuthUser(String method, String login, String time, String password) throws Exception {
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 + "')");
@ -272,29 +269,25 @@ public class UserResource {
if (login.length() < 6) {
throw new InputException("login", "Authentiocate-method-error (email or login too small: '" + login + "')");
}
if(password == null || password.length() != 128) {
if (password == null || password.length() != 128) {
throw new InputException("password", "null password, or wrong hash size");
}
}
// email or login?
String query = "login";
if (login.contains("@")) {
query = "email";
}
UserAuth user = SqlWrapper.getWhere(UserAuth.class,
List.of(
new WhereCondition(query, "=", login)
),
false );
final UserAuth user = SqlWrapper.getWhere(UserAuth.class, new QuerryCondition(query, "=", login), false);
if (user == null) {
throw new FailException(Response.Status.PRECONDITION_FAILED , "FAIL Authentiocate-wrong email/login '" + login + "')");
throw new FailException(Response.Status.PRECONDITION_FAILED, "FAIL Authentiocate-wrong email/login '" + login + "')");
}
// Check the password:
String passwodCheck = getSHA512("login='" + login + "';pass='" + user.password + "';date='" + time + "'");
final String passwodCheck = getSHA512("login='" + login + "';pass='" + user.password + "';date='" + time + "'");
if (!passwodCheck.contentEquals(password)) {
throw new FailException(Response.Status.PRECONDITION_FAILED , "Password error ...");
throw new FailException(Response.Status.PRECONDITION_FAILED, "Password error ...");
}
logger.debug(" ==> pass nearly all test : admin={} blocked={} removed={}", user.admin, user.blocked, user.removed);
this.logger.debug(" ==> pass nearly all test : admin={} blocked={} removed={}", user.admin, user.blocked, user.removed);
if (user.blocked || user.removed) {
throw new FailException(Response.Status.UNAUTHORIZED, "FAIL Authentiocate");
}
@ -303,31 +296,31 @@ public class UserResource {
@POST
@Path("/get_token")
@PermitAll
@PermitAll
@Consumes(MediaType.APPLICATION_JSON)
public GetToken getToken(DataGetToken data) throws Exception {
logger.info("User Authenticate: {}", data.login());
UserAuth user = checkAuthUser(data.method(), data.login(), data.time(), data.password());
public GetToken getToken(final DataGetToken data) throws Exception {
this.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
int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime();
final int expirationTimeInMinutes = ConfigVariable.getAuthExpirationTime();
// Get the USER Right (Note: by construction KARSO have application ID = KARSO_INITIALISATION_ID
Map<String, Object> ssoRight = RightResource.getUserRight(user.id, Initialization.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);
Map<String, Object> outRight = new HashMap<>();
String applicationName = "karso";
this.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...
String ret = JWTWrapper.generateJWToken(user.id, user.login, "KarAuth", applicationName, outRight, expirationTimeInMinutes);
final String ret = JWTWrapper.generateJWToken(user.id, user.login, "KarAuth", applicationName, outRight, expirationTimeInMinutes);
// Update last connection:
UserAuth newUser = new UserAuth();
final UserAuth newUser = new UserAuth();
newUser.lastConnection = Timestamp.valueOf(LocalDateTime.now());
SqlWrapper.update(newUser, user.id, List.of("lastConnection"));
@ -335,55 +328,23 @@ public class UserResource {
return new GetToken(ret);
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
public static String bytesToHex(final byte[] bytes) {
final StringBuilder sb = new StringBuilder();
for (final byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public String getSHA512(String passwordToHash){
public String getSHA512(final String passwordToHash) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
final MessageDigest md = MessageDigest.getInstance("SHA-512");
final byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
return bytesToHex(bytes);
} catch (NoSuchAlgorithmException e) {
} catch (final NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -4,44 +4,42 @@ import java.sql.Timestamp;
import java.time.Instant;
import org.kar.archidata.filter.AuthenticationFilter;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.sqlWrapper.SqlWrapper;
import org.kar.karso.model.ApplicationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.ext.Provider;
//@PreMatching
@Provider
@Priority(Priorities.AUTHENTICATION)
public class KarsoAuthenticationFilter extends AuthenticationFilter {
final Logger logger = LoggerFactory.getLogger(KarsoAuthenticationFilter.class);
//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() {
//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");
}
@Override
protected UserByToken validateToken(String authorization) throws Exception {
protected UserByToken validateToken(final String authorization) throws Exception {
if (authorization == null || authorization.length() < 25) {
System.out.println("Application authentication too short '" + authorization + "'");
return null;
}
String[] elems = authorization.split(":");
final String[] elems = authorization.split(":");
if (elems.length != 2) {
System.out.println("Application authentication split error '" + authorization + "'");
return null;
}
Long indexToken = Long.parseLong(elems[0]);
final Long indexToken = Long.parseLong(elems[0]);
ApplicationToken value = SqlWrapper.get(ApplicationToken.class, indexToken);
final ApplicationToken value = SqlWrapper.get(ApplicationToken.class, indexToken);
if (value == null) {
System.out.println("Application authentication can not find id '" + authorization + "'");
return null;
@ -59,13 +57,13 @@ public class KarsoAuthenticationFilter extends AuthenticationFilter {
// ----------------------------------
// -- All is good !!!
// ----------------------------------
// We are in transition phase the user element will be removed
UserByToken userByToken = new UserByToken();
userByToken.id = value.id;
userByToken.name = value.name;
userByToken.parentId = value.parentId;
userByToken.type = UserByToken.TYPE_APPLICATION;
userByToken.right.put("APPLICATION", true);
return userByToken;
}
// We are in transition phase the user element will be removed
final UserByToken userByToken = new UserByToken();
userByToken.id = value.id;
userByToken.name = value.name;
userByToken.parentId = value.parentId;
userByToken.type = UserByToken.TYPE_APPLICATION;
userByToken.right.put("APPLICATION", true);
return userByToken;
}
}

View File

@ -9,14 +9,14 @@ import org.kar.karso.model.Settings;
import org.kar.karso.model.UserAuth;
public class Initialization extends MigrationSqlStep {
public static final int KARSO_INITIALISATION_ID = 1;
public static final int KARSO_INITIALISATION_ID = 1;
@Override
public String getName() {
return "Initialization";
}
public Initialization() throws Exception {
addClass(Settings.class);
addClass(UserAuth.class);
@ -24,7 +24,7 @@ public class Initialization extends MigrationSqlStep {
addClass(ApplicationToken.class);
addClass(RightDescription.class);
addClass(Right.class);
addAction("""
INSERT INTO `application` (`id`, `name`, `description`, `redirect`, `redirectDev`, `notification`, `ttl`) VALUES
(1, 'karso', 'Root SSO interface', 'http://atria-soft/karso', '', '', 666);
@ -70,6 +70,7 @@ public class Initialization extends MigrationSqlStep {
addAction("""
ALTER TABLE `rightDescription` AUTO_INCREMENT = 1000;
""");
display();
}
}

View File

@ -13,52 +13,43 @@ CREATE TABLE `application` (
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("application")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "application")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Application extends GenericTable{
@SQLLimitSize(256)
public String name;
@SQLLimitSize(2048)
public String description;
@SQLLimitSize(2048)
@SQLNotNull
public String redirect;
@SQLLimitSize(2048)
@SQLDefault("'http://localhost:4200/sso/'")
public String redirectDev;
@SQLLimitSize(2048)
@SQLDefault("'http://localhost:4200/sso/notification'")
public String notification;
@SQLNotNull
@SQLComment("Expiration time ")
@SQLDefault("666")
public Integer ttl;
@SQLNotNull
@SQLComment("Right is manage with Karso")
@SQLDefault("0")
public Boolean manageRight;
public Application() {
}
@Override
public String toString() {
return "Application{" +
"id=" + id +
", description='" + description + '\'' +
", redirect='" + redirect + '\'' +
", redirectDev='" + redirectDev + '\'' +
", notification='" + notification + '\'' +
", ttl='" + ttl + '\'' +
'}';
}
public class Application extends GenericTable {
@Column(length = 256)
public String name;
@Column(length = 2048)
public String description;
@Column(length = 2048, nullable = false)
public String redirect;
@Column(length = 2048)
@SQLDefault("'http://localhost:4200/sso/'")
public String redirectDev;
@Column(length = 2048)
@SQLDefault("'http://localhost:4200/sso/notification'")
public String notification;
@Column(nullable = false)
@SQLComment("Expiration time ")
@SQLDefault("666")
public Integer ttl;
@Column(nullable = false)
@SQLComment("Right is manage with Karso")
@SQLDefault("0")
public Boolean manageRight;
public Application() {}
@Override
public String toString() {
return "Application{" + "id=" + this.id + ", description='" + this.description + '\'' + ", redirect='" + this.redirect + '\'' + ", redirectDev='" + this.redirectDev + '\'' + ", notification='"
+ this.notification + '\'' + ", ttl='" + this.ttl + '\'' + '}';
}
}

View File

@ -1,14 +1,15 @@
package org.kar.karso.model;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericToken;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("applicationToken")
import jakarta.persistence.Table;
@Table(name = "applicationToken")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApplicationToken extends GenericToken {
}

View File

@ -1,35 +1,33 @@
package org.kar.karso.model;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLForeignKey;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("right")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "right")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Right extends GenericTable {
@SQLNotNull
@SQLComment("application-ID that have the reference of the right")
@SQLForeignKey("application")
public long applicationId;
@SQLNotNull
@SQLComment("user-ID ")
@SQLForeignKey("user")
public long userId;
@SQLNotNull
@SQLComment("rightDescription-ID of the right description")
@SQLForeignKey("rightDescription")
public long rightDescriptionId;
@SQLNotNull
@SQLLimitSize(1024)
@SQLComment("Value of the right")
public String value;
@Column(nullable = false)
@SQLComment("application-ID that have the reference of the right")
@SQLForeignKey("application")
public long applicationId;
@Column(nullable = false)
@SQLComment("user-ID ")
@SQLForeignKey("user")
public long userId;
@Column(nullable = false)
@SQLComment("rightDescription-ID of the right description")
@SQLForeignKey("rightDescription")
public long rightDescriptionId;
@Column(length = 1024, nullable = false)
@SQLComment("Value of the right")
public String value;
}

View File

@ -4,39 +4,35 @@ import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLForeignKey;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("rightDescription")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "rightDescription")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class RightDescription extends GenericTable {
@SQLNotNull
@SQLComment("Application id that have the reference of the right")
@SQLForeignKey("application")
public long applicationId;
@SQLNotNull
@SQLLimitSize(64)
@SQLComment("Key of the property")
public String key;
@SQLNotNull
@SQLLimitSize(1024)
@SQLComment("Title of the right")
public String title;
@SQLNotNull
@SQLLimitSize(1024)
@SQLComment("Description of the right")
public String description;
@SQLLimitSize(1024)
@SQLComment("default value if Never set")
public String defaultValue;
@SQLNotNull
@SQLLimitSize(16)
@SQLComment("Type of the property")
@SQLDefault("\"BOOLEAN\"")
public String type = "BOOLEAN"; // this is a place-holder (current type supported BOOLEAN)
@Column(nullable = false)
@SQLComment("Application id that have the reference of the right")
@SQLForeignKey("application")
public long applicationId;
@Column(length = 64, nullable = false)
@SQLComment("Key of the property")
public String key;
@Column(length = 1024, nullable = false)
@SQLComment("Title of the right")
public String title;
@Column(length = 1024, nullable = false)
@SQLComment("Description of the right")
public String description;
@Column(length = 1024)
@SQLComment("default value if Never set")
public String defaultValue;
@Column(length = 16, nullable = false)
@SQLComment("Type of the property")
@SQLDefault("\"BOOLEAN\"")
public String type = "BOOLEAN"; // this is a place-holder (current type supported BOOLEAN)
}

View File

@ -13,43 +13,37 @@ CREATE TABLE `application` (
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.persistence.Column;
import jakarta.persistence.Table;
enum PropertyType {
STRING,
NUMBER,
BOOLEAN,
STRING, NUMBER, BOOLEAN,
}
@SQLTableName ("settings")
@Table(name = "settings")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Settings extends GenericTable {
@SQLLimitSize(512)
@SQLNotNull
public String key;
@SQLComment("Right for the specific element(ADMIN [rw] USER [rw] other [rw])")
@SQLNotNull
@SQLLimitSize(6)
@SQLDefault("\"rw----\"")
public String right;
@SQLComment("Type Of the data")
@SQLNotNull
//public PropertyType type;
@SQLLimitSize(10)
public String type;
@SQLComment("Value of the configuration")
@SQLNotNull
public String value;
@Column(length = 512, nullable = false)
public String key;
@SQLComment("Right for the specific element(ADMIN [rw] USER [rw] other [rw])")
@Column(length = 6, nullable = false)
@SQLDefault("\"rw----\"")
public String right;
@SQLComment("Type Of the data")
@Column(length = 10, nullable = false)
public String type;
@SQLComment("Value of the configuration")
@Column(nullable = false)
public String value;
@Override
public String toString() {
return "Settings [key=" + key + ", value=" + value + ", id=" + id + ", deleted=" + deleted + "]";
return "Settings [key=" + this.key + ", value=" + this.value + ", id=" + this.id + ", deleted=" + this.deleted + "]";
}
}

View File

@ -6,38 +6,36 @@ import java.util.List;
import org.kar.archidata.annotation.SQLComment;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableLinkGeneric;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.annotation.addOn.SQLTableExternalLink;
import org.kar.archidata.model.User;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("user")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "user")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserAuth extends User {
@SQLLimitSize(128)
@SQLNotNull
@Column(length = 128, nullable = false)
public String password;
/*
@SQLLimitSize(128)
/*
@Column(length = 128)
public String passwordChange; //!< When change a password, the new password is set in temporary area and wait the email validation
@SQLLimitSize(128)
@Column(length = 128)
public String passwordValidation; //!< UniqueId to validate the new password
*/
@SQLLimitSize(512)
@SQLNotNull
*/
@Column(length = 512, nullable = false)
public String email;
public Timestamp emailValidate; // time of validation
@SQLLimitSize(512)
@Column(length = 512)
public String newEmail;
@SQLDefault("'0'")
@SQLNotNull
@SQLDefault("'0'")
@Column(nullable = false)
public boolean avatar = false;
@SQLComment("List of accessible application (if not set the application is not available)")
@SQLTableLinkGeneric
public List<Long> applications = null;
@SQLComment("List of accessible application (if not set the application is not available)")
@SQLTableExternalLink
public List<Long> applications = null;
}

View File

@ -2,21 +2,20 @@ package org.kar.karso.model;
import org.kar.archidata.annotation.SQLDefault;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLLimitSize;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.User;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("user")
import jakarta.persistence.Column;
import jakarta.persistence.Table;
@Table(name = "user")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserAuthGet extends User {
@SQLLimitSize(512)
@SQLNotNull
public class UserAuthGet extends User {
@Column(length = 512, nullable = false)
public String email;
@SQLDefault("'0'")
@SQLNotNull
@SQLDefault("'0'")
@Column(nullable = false)
public boolean avatar = false;
}

View File

@ -11,15 +11,16 @@ CREATE TABLE `application` (
*/
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLTableName;
import org.kar.archidata.model.GenericTable;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("user_link_application")
import jakarta.persistence.Table;
@Table(name = "user_link_application")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserLinkApplication extends GenericTable{
public long user_id;
public long application_id;
public class UserLinkApplication extends GenericTable {
public long user_id;
public long application_id;
}

View File

@ -1,4 +1,5 @@
package test.kar.karso;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
@ -13,7 +14,6 @@ import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.kar.archidata.SqlWrapper;
import org.kar.archidata.exception.RESTErrorResponseExeption;
import org.kar.archidata.model.GetToken;
import org.kar.archidata.util.ConfigBaseVariable;
@ -29,112 +29,108 @@ import com.nimbusds.jwt.JWTClaimsSet;
@ExtendWith(StepwiseExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestBase {
final static Logger logger = LoggerFactory.getLogger(WebLauncherTest.class);
private final static Logger LOGGER = LoggerFactory.getLogger(TestBase.class);
static WebLauncherTest webInterface = null;
static RESTApi api = null;
public void login(String login, String password) {
public void login(final String login, final String password) {
try {
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, "v1", "202515252", password));
api.setToken(token.jwt());
} catch (Exception ex) {
} catch (final Exception ex) {
Assertions.fail("Can not get Authentication for '" + login + "' ==> " + ex.getMessage());
}
}
public void loginAdmin() {
login("karadmin", "adminA@666");
}
@BeforeAll
public static void configureWebServer() throws Exception {
logger.info("configure server ...");
LOGGER.info("configure server ...");
webInterface = new WebLauncherTest();
logger.info("Create DB");
String dbName = "sdfsdfsdfsfsdfsfsfsfsdfsdfsd";
boolean data = SqlWrapper.isDBExist(dbName);
logger.error("exist: {}", data);
data = SqlWrapper.createDB(dbName);
logger.error("create: {}", data);
data = SqlWrapper.isDBExist(dbName);
logger.error("exist: {}", data);
System.exit(-1);
logger.info("Start REST (BEGIN)");
LOGGER.info("Create DB");
try {
webInterface.migrateDB();
} catch (final Exception ex) {
ex.printStackTrace();
LOGGER.error("Detect an error: {}", ex.getMessage());
}
LOGGER.info("Start REST (BEGIN)");
webInterface.process();
logger.info("Start REST (DONE)");
LOGGER.info("Start REST (DONE)");
api = new RESTApi(ConfigBaseVariable.apiAdress);
}
@AfterAll
public static void stopWebServer() throws InterruptedException {
logger.info("Kill the web server");
LOGGER.info("Kill the web server");
webInterface = null;
// TODO: do it better...
}
@Order(1)
@Test
//@RepeatedTest(10)
public void checkHealthCheck() throws Exception {
HealthResult result = api.get(HealthResult.class, "health_check");
Assertions.assertEquals(result.value(), "alive and kicking");
final HealthResult result = api.get(HealthResult.class, "health_check");
Assertions.assertEquals(result.value(), "alive and kicking");
}
@Order(2)
@Test
public void checkHealthCheckWrongAPI() throws Exception {
Assertions.assertThrows(RESTErrorResponseExeption.class, ()->api.get(HealthResult.class, "health_checks"));
Assertions.assertThrows(RESTErrorResponseExeption.class, () -> api.get(HealthResult.class, "health_checks"));
}
@Order(3)
@Test
public void firstUserConnect() throws Exception {
GetToken result = api.post(GetToken.class, "users/get_token", DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
String[] splitted = result.jwt().split("\\.");
final GetToken result = api.post(GetToken.class, "users/get_token", DataGetToken.generate("karadmin", "v1", "202515252", "adminA@666"));
final String[] splitted = result.jwt().split("\\.");
Assertions.assertEquals(3, splitted.length);
String authorization = result.jwt();
logger.debug(" validate token : " + authorization);
// Note with local access we get the internal key of the system.
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
Assertions.assertNotNull(ret);
// check userID
String userUID = ret.getSubject();
long id = Long.parseLong(userUID);
Assertions.assertEquals(0, id);
String name = (String)ret.getClaim("login");
Assertions.assertEquals("karadmin", name);
Object rowRight = ret.getClaim("right");
Assertions.assertNotNull(rowRight);
Map<String, Map<String,Object>> rights = (Map<String, Map<String,Object>>) ret.getClaim("right");
// Check if the element contain the basic keys:
Assertions.assertEquals(rights.size(), 1);
Assertions.assertTrue(rights.containsKey("karso"));
Map<String, Object> applRight = rights.get("karso");
//logger.error("full right: {}", applRight);
Assertions.assertEquals(applRight.size(), 2);
Assertions.assertTrue(applRight.containsKey("ADMIN"));
Assertions.assertEquals(true, applRight.get("ADMIN"));
Assertions.assertTrue(applRight.containsKey("USER"));
Assertions.assertEquals(true, applRight.get("USER"));
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, applRight, rowRight);
final String authorization = result.jwt();
LOGGER.debug(" validate token : " + authorization);
// Note with local access we get the internal key of the system.
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
Assertions.assertNotNull(ret);
// check userID
final String userUID = ret.getSubject();
final long id = Long.parseLong(userUID);
Assertions.assertEquals(0, id);
final String name = (String) ret.getClaim("login");
Assertions.assertEquals("karadmin", name);
final Object rowRight = ret.getClaim("right");
Assertions.assertNotNull(rowRight);
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
// Check if the element contain the basic keys:
Assertions.assertEquals(rights.size(), 1);
Assertions.assertTrue(rights.containsKey("karso"));
final Map<String, Object> applRight = rights.get("karso");
//logger.error("full right: {}", applRight);
Assertions.assertEquals(applRight.size(), 2);
Assertions.assertTrue(applRight.containsKey("ADMIN"));
Assertions.assertEquals(true, applRight.get("ADMIN"));
Assertions.assertTrue(applRight.containsKey("USER"));
Assertions.assertEquals(true, applRight.get("USER"));
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, applRight, rowRight);
//Assertions.assertEquals("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9", splitted[0]);
//Assertions.assertEquals("eyJzdWIiOiIwIiwiYXBwbGljYXRpb24iOiJrYXJzbyIsImlzcyI6IkthckF1dGgiLCJyaWdodCI6eyJrYXJzbyI6eyJBRE1JTiI6dHJ1ZSwiVVNFUiI6dHJ1ZX19LCJsb2dpbiI6ImthcmFkbWluIiwiZXhwIjoxNjg0MTk5MTkzLCJpYXQiOjE2ODI3NTU0MjV9", splitted[1]);
// TODO ... Assertions.assertEquals("????", splitted[2]);
}
public void checkFail(String type, String urlOffset, int errorStatus) {
public void checkFail(final String type, final String urlOffset, final int errorStatus) {
checkFail(type, urlOffset, errorStatus, null);
}
public void checkFail(String type, String urlOffset, int errorStatus, String data) {
logger.info("Test API: url={} urlOffset={}", type, urlOffset);
public void checkFail(final String type, final String urlOffset, final int errorStatus, final String data) {
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
try {
if ("GET".equals(type)) {
api.get(String.class, urlOffset);
@ -146,22 +142,24 @@ public class TestBase {
api.delete(String.class, urlOffset);
}
Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (RESTErrorResponseExeption ex) {
} catch (final RESTErrorResponseExeption ex) {
if (errorStatus != ex.status) {
logger.error("Fail in test with the wrong return errors: {}", ex.toString());
LOGGER.error("Fail in test with the wrong return errors: {}", ex.toString());
}
Assertions.assertEquals(errorStatus, ex.status);
} catch (Exception ex) {
logger.error("Unexpected throw error: {}", ex);
} catch (final Exception ex) {
LOGGER.error("Unexpected throw error: {}", ex);
Assertions.fail("Unexpected throws...");
}
}
public void checkWork(String type, String urlOffset) {
public void checkWork(final String type, final String urlOffset) {
checkWork(type, urlOffset, null);
}
public void checkWork(String type, String urlOffset, String data) {
logger.info("Test API: url={} urlOffset={}", type, urlOffset);
public void checkWork(final String type, final String urlOffset, final String data) {
LOGGER.info("Test API: url={} urlOffset={}", type, urlOffset);
try {
if ("GET".equals(type)) {
api.get(String.class, urlOffset);
@ -173,14 +171,15 @@ public class TestBase {
api.delete(String.class, urlOffset);
}
//Assertions.fail("Request on URL does not fail as expected: '" + type + "' url='" + urlOffset + "'");
} catch (RESTErrorResponseExeption ex) {
} catch (final RESTErrorResponseExeption ex) {
Assertions.fail("Must not fail ... " + ex.toString());
} catch (Exception ex) {
logger.error("Unexpected throw error: {}", ex);
} catch (final Exception ex) {
LOGGER.error("Unexpected throw error: {}", ex);
Assertions.fail("Unexpected throws...");
}
}
@Order(4)
@Test
public void checkUnAuthorizedAPI() throws Exception {
@ -200,34 +199,33 @@ public class TestBase {
checkFail("GET", "application/small", 401);
checkFail("GET", "application/get_token", 401);
checkFail("GET", "application/return", 401);
// /application_token/ section:
checkFail("GET", "application_token/0", 401);
checkFail("DELETE", "application_token/0/5", 401);
checkFail("DELETE", "application_token/0/create", 401);
// /front/*
checkFail("GET", "front", 404); // no index in test section
// health check
checkWork("GET", "health_check");
// public_key (only application)
checkFail("GET", "public_key", 401);
checkFail("GET", "public_key/pem", 401);
// /right
checkFail("GET", "right", 401);
checkFail("POST", "right", 401, "{}");
checkFail("GET", "right/0", 401);
checkFail("PUT", "right/0", 401, "{}");
checkFail("DELETE", "right/0", 401);
// /system_config
checkWork("GET", "system_config/is_sign_up_availlable");
checkFail("GET", "system_config/key/skjdfhkjsdhfkjsh", 401);
checkFail("PUT", "system_config/key/skjdfhkjsdhfkjsh", 401, "{}");
// /users
checkFail("GET", "users", 401);
checkFail("GET", "users/0", 401);
@ -242,46 +240,43 @@ public class TestBase {
checkWork("GET", "users/check_email?email=admin@admin.ZZZ");
checkFail("GET", "users/check_email?email=ksjhdkjfhskjdh", 404);
// not testable : get_token
}
@Order(5)
@Test
public void testMeWithToken() throws Exception {
this.loginAdmin();
String result = api.get(String.class, "users/me");
Assertions.assertEquals("{\"id\":0,\"login\":\"karadmin\"}", result);
loginAdmin();
final String result = api.get(String.class, "users/me");
Assertions.assertEquals("{\"id\":0,\"login\":\"karadmin\"}", result);
}
}
class StepwiseExtension implements ExecutionCondition, TestExecutionExceptionHandler {
@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext extensionContext) {
ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
ExtensionContext.Store store = storeFor(extensionContext, namespace);
String value = store.get(StepwiseExtension.class, String.class);
return value == null ? ConditionEvaluationResult.enabled("No test failures in stepwise tests") :
ConditionEvaluationResult.disabled(String.format("Stepwise test disabled due to previous failure in '%s'", value));
}
@Override
public void handleTestExecutionException(ExtensionContext extensionContext, Throwable throwable) throws Throwable {
ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
ExtensionContext.Store store = storeFor(extensionContext, namespace);
store.put(StepwiseExtension.class, extensionContext.getDisplayName());
throw throwable;
}
private ExtensionContext.Namespace namespaceFor(ExtensionContext extensionContext){
return ExtensionContext.Namespace.create(StepwiseExtension.class, extensionContext.getParent());
}
private ExtensionContext.Store storeFor(ExtensionContext extensionContext, ExtensionContext.Namespace namespace){
return extensionContext.getParent().get().getStore(namespace);
}
@Override
public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext extensionContext) {
final ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
final ExtensionContext.Store store = storeFor(extensionContext, namespace);
final String value = store.get(StepwiseExtension.class, String.class);
return value == null ? ConditionEvaluationResult.enabled("No test failures in stepwise tests")
: ConditionEvaluationResult.disabled(String.format("Stepwise test disabled due to previous failure in '%s'", value));
}
@Override
public void handleTestExecutionException(final ExtensionContext extensionContext, final Throwable throwable) throws Throwable {
final ExtensionContext.Namespace namespace = namespaceFor(extensionContext);
final ExtensionContext.Store store = storeFor(extensionContext, namespace);
store.put(StepwiseExtension.class, extensionContext.getDisplayName());
throw throwable;
}
private ExtensionContext.Namespace namespaceFor(final ExtensionContext extensionContext) {
return ExtensionContext.Namespace.create(StepwiseExtension.class, extensionContext.getParent());
}
private ExtensionContext.Store storeFor(final ExtensionContext extensionContext, final ExtensionContext.Namespace namespace) {
return extensionContext.getParent().get().getStore(namespace);
}
}

View File

@ -9,20 +9,20 @@ import org.slf4j.LoggerFactory;
public class WebLauncherTest extends WebLauncher {
final Logger logger = LoggerFactory.getLogger(WebLauncherTest.class);
public WebLauncherTest() {
logger.debug("Configure REST system");
this.logger.debug("Configure REST system");
// for local test:
ConfigBaseVariable.apiAdress = "http://127.0.0.1:12345/test/api/";
ConfigBaseVariable.dbPort = "3306";
// create a unique key for test ==> not retrieve the token every load...
ConfigVariable.uuid_for_key_generation = "lkjlkjlkjlmkjqmwlsdkjqfsdlkf,nmQLSDK,NFMQLKSdjmlKQJSDMLQK,S;ndmLQKZNERMA,ÉL";
// for the test we a in memory sqlite..
////ConfigBaseVariable.dbType = "sqlite";
////ConfigBaseVariable.dbHost = "memory";
// for the test we a in memory sqlite..
ConfigBaseVariable.dbType = "sqlite";
ConfigBaseVariable.dbHost = "memory";
// for test we need to connect all time the DB
////ConfigBaseVariable.dbKeepConnected = "true";
ConfigBaseVariable.dbKeepConnected = "true";
ConfigBaseVariable.dbHost = "localhost";
ConfigBaseVariable.dbUser = "root";