base of new securisation model
All checks were successful
WEB karideo and rabbit/archidata/pipeline/head This commit looks good

This commit is contained in:
Edouard DUPIN 2023-01-28 00:15:03 +01:00
parent 949fc0b05c
commit 50cb92703b
12 changed files with 240 additions and 116 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.2.6</version>
<version>0.3.1</version>
<properties>
<jaxrs.version>2.1</jaxrs.version>
<jersey.version>2.32</jersey.version>

View File

@ -0,0 +1,5 @@
package org.kar.archidata;
public class MigrationAction {
}

View File

@ -616,6 +616,45 @@ public class SqlWrapper {
public static <T> List<T> getsWhere(Class<T> clazz, List<WhereCondition> condition, boolean full, Integer linit) throws Exception {
return getsWhere(clazz, condition, null, full, linit);
}
public static void whereAppendQuery(StringBuilder query, String tableName, List<WhereCondition> condition, boolean exclude_deleted) throws ExceptionDBInterface {
// Check if we have a condition to generate
if (condition == null || condition.size() == 0) {
return;
}
query.append(" WHERE ");
boolean first = true;
for (WhereCondition elem : condition) {
if (first) {
first = false;
} else {
query.append(" AND ");
}
query.append(tableName);
query.append(".");
query.append(elem.key());
query.append(" ");
query.append(elem.comparator());
query.append(" ?");
}
if (exclude_deleted) {
if (!first) {
query.append(" AND ");
}
query.append(tableName);
query.append(".deleted = false ");
}
}
public static void whereInjectValue(PreparedStatement ps, List<WhereCondition> condition) throws Exception {
// Check if we have a condition to generate
if (condition == null || condition.size() == 0) {
return;
}
int iii = 1;
for (WhereCondition elem : condition) {
addElement(ps, elem.Value(), iii++);
}
}
public static <T> List<T> getsWhere(Class<T> clazz, List<WhereCondition> condition, String orderBy, boolean full, Integer linit) throws Exception {
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
List<T> outs = new ArrayList<>();
@ -659,24 +698,7 @@ public class SqlWrapper {
query.append(" FROM `");
query.append(tableName);
query.append("` ");
query.append(" WHERE ");
if (condition.size() == 0) {
throw new ExceptionDBInterface(4575643, tableName + " ==> request where without parameters");
}
boolean first = true;
for (WhereCondition elem : condition) {
if (first) {
first = false;
} else {
query.append(" AND ");
}
query.append(tableName);
query.append(".");
query.append(elem.key());
query.append(" ");
query.append(elem.comparator());
query.append(" ?");
}
whereAppendQuery(query, tableName, condition, true);
if (orderBy != null && orderBy.length() >= 1) {
query.append(" ORDER BY ");
//query.append(tableName);
@ -695,10 +717,7 @@ public class SqlWrapper {
//System.out.println("generate the query: '" + query.toString() + "'");
// prepare the request:
PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS);
int iii = 1;
for (WhereCondition elem : condition) {
addElement(ps, elem.Value(), iii++);
}
whereInjectValue(ps, condition);
// execute the request
ResultSet rs = ps.executeQuery();
while (rs.next()) {
@ -1000,35 +1019,51 @@ public class SqlWrapper {
public static void delete(Class<?> clazz, long id) throws Exception {
// TODO: I am not sure this is a real good idea.
}
public static void setDelete(Class<?> clazz, long id) throws Exception {
public static int setDelete(Class<?> clazz, long id) throws Exception {
return setDeleteWhere(clazz, List.of(
new WhereCondition("id", "=", id)
));
}
public static int setDeleteWhere(Class<?> clazz, List<WhereCondition> condition) throws Exception {
String tableName = getTableName(clazz);
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
String query = "UPDATE `" + tableName + "` SET `modify_date`=now(3), `deleted`=true WHERE `id` = ?";
StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
query.append("` SET `modify_date`=now(3), `deleted`=true ");
whereAppendQuery(query, tableName, condition, false);
try {
PreparedStatement ps = entry.connection.prepareStatement(query);
int iii = 1;
ps.setLong(iii++, id);
ps.executeUpdate();
} catch (SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
PreparedStatement ps = entry.connection.prepareStatement(query.toString());
whereInjectValue(ps, condition);
int affectedRows = ps.executeUpdate();
return affectedRows;
} finally {
entry.close();
entry = null;
}
}
public static void unsetDelete(Class<?> clazz, long id) throws Exception {
public static int unsetDelete(Class<?> clazz, long id) throws Exception {
return unsetDeleteWhere(clazz, List.of(
new WhereCondition("id", "=", id)
));
}
public static int unsetDeleteWhere(Class<?> clazz, List<WhereCondition> condition) throws Exception {
String tableName = getTableName(clazz);
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
String query = "UPDATE `" + tableName + "` SET `modify_date`=now(3), `deleted`=false WHERE `id` = ?";
StringBuilder query = new StringBuilder();
query.append("UPDATE `");
query.append(tableName);
query.append("` SET `modify_date`=now(3), `deleted`=false ");
whereAppendQuery(query, tableName, condition, false);
try {
PreparedStatement ps = entry.connection.prepareStatement(query);
int iii = 1;
ps.setLong(iii++, id);
ps.executeUpdate();
} catch (SQLException ex) {
ex.printStackTrace();
throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage());
PreparedStatement ps = entry.connection.prepareStatement(query.toString());
whereInjectValue(ps, condition);
int affectedRows = ps.executeUpdate();
return affectedRows;
} finally {
entry.close();
entry = null;
@ -1228,4 +1263,5 @@ public class SqlWrapper {
return ((SQLLimitSize) annotation[0]).value();
}
}

View File

@ -20,6 +20,7 @@ import javax.ws.rs.ext.Provider;
import org.kar.archidata.UserDB;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.model.User;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.util.JWTWrapper;
import com.nimbusds.jwt.JWTClaimsSet;
@ -40,6 +41,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
private ResourceInfo resourceInfo;
private static final String AUTHENTICATION_SCHEME = "Yota";
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
@ -84,63 +86,68 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
}
}
//System.out.println("authorizationHeader: " + authorizationHeader);
/*
System.out.println(" -------------------------------");
// this get the parameters inside the pre-parsed element in the request ex: @Path("thumbnail/{id}") generate a map with "id"
MultivaluedMap<String, String> pathparam = requestContext.getUriInfo().getPathParameters();
for (Entry<String, List<String>> item: pathparam.entrySet()) {
System.out.println(" param: " + item.getKey() + " ==>" + item.getValue());
}
System.out.println(" -------------------------------");
// need to add "@QueryParam("p") String token, " in the model
//MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
for (Entry<String, List<String>> item: quaryparam.entrySet()) {
System.out.println(" query: " + item.getKey() + " ==>" + item.getValue());
}
System.out.println(" -------------------------------");
List<PathSegment> segments = requestContext.getUriInfo().getPathSegments();
for (final PathSegment item: segments) {
System.out.println(" query: " + item.getPath() + " ==>" + item.getMatrixParameters());
}
System.out.println(" -------------------------------");
MultivaluedMap<String, String> headers = requestContext.getHeaders();
for (Entry<String, List<String>> item: headers.entrySet()) {
System.out.println(" headers: " + item.getKey() + " ==>" + item.getValue());
}
System.out.println(" -------------------------------");
*/
// Validate the Authorization header data Model "Yota userId:token"
if (!isTokenBasedAuthentication(authorizationHeader)) {
// System.out.println("authorizationHeader: " + authorizationHeader);
boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
if (!isApplicationToken && !isJwtToken) {
System.out.println("REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
abortWithUnauthorized(requestContext);
return;
}
// check JWT token (basic:)
// Extract the token from the Authorization header (Remove "Yota ")
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
System.out.println("token: " + token);
User user = null;
try {
user = validateToken(token);
} catch (Exception e) {
System.out.println("Fail to validate token: " + e.getMessage());
abortWithUnauthorized(requestContext);
return;
}
if (user == null) {
System.out.println("get a NULL user ...");
abortWithUnauthorized(requestContext);
return;
UserByToken userByToken = null;
if (isJwtToken) {
// Extract the token from the Authorization header (Remove "Yota ")
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
//System.out.println("token: " + token);
try {
user = validateJwtToken(token);
} catch (Exception e) {
System.out.println("Fail to validate token: " + e.getMessage());
abortWithUnauthorized(requestContext);
return;
}
if (user == null) {
System.out.println("get a NULL user ...");
abortWithUnauthorized(requestContext);
return;
}
// We are in transition phase the user element will be removed
userByToken = new UserByToken();
userByToken.id = user.id;
userByToken.name = user.login;
userByToken.parentId = null;
userByToken.type = UserByToken.TYPE_USER;
if (user.removed || user.blocked) {
userByToken.type = null;
} else if (user.admin) {
userByToken.right.put("ADMIN", true);
userByToken.right.put("USER", true);
} else {
userByToken.right.put("USER", true);
}
} else {
// Extract the token from the Authorization header (Remove "Zota ")
String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
//System.out.println("token: " + token);
try {
userByToken = validateToken(token);
} catch (Exception e) {
System.out.println("Fail to validate token: " + e.getMessage());
abortWithUnauthorized(requestContext);
return;
}
if (userByToken == null) {
System.out.println("get a NULL application ...");
abortWithUnauthorized(requestContext);
return;
}
}
// create the security context model:
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
MySecurityContext userContext = new MySecurityContext(user, scheme);
MySecurityContext userContext = new MySecurityContext(user, userByToken, scheme);
// retrieve the allowed right:
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
List<String> roles = Arrays.asList(rolesAnnotation.value());
@ -152,7 +159,6 @@ public class AuthenticationFilter implements ContainerRequestFilter {
break;
}
}
//Is user valid?
if( ! haveRight) {
System.out.println("REJECTED not enought right : " + requestContext.getUriInfo().getPath() + " require: " + roles);
@ -160,7 +166,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
return;
}
requestContext.setSecurityContext(userContext);
System.out.println("Get local user : " + user);
// System.out.println("Get local user : " + user + " / " + userByToken);
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
@ -169,6 +175,14 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_SCHEME.toLowerCase() + " ");
}
private boolean isApplicationTokenBasedAuthentication(String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " ");
}
private void abortWithUnauthorized(ContainerRequestContext requestContext) {
@ -181,7 +195,12 @@ public class AuthenticationFilter implements ContainerRequestFilter {
.build());
}
private User validateToken(String authorization) throws Exception {
protected UserByToken validateToken(String authorization) throws Exception {
System.out.println("dsfgsdgsdfgsdgf");
return null;
}
// must be override to be good implemenres
protected User validateJwtToken(String authorization) throws Exception {
System.out.println(" validate token : " + authorization);
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...

View File

@ -1,15 +1,18 @@
package org.kar.archidata.filter;
import org.kar.archidata.model.User;
import org.kar.archidata.model.UserByToken;
import java.security.Principal;
public class GenericContext implements Principal {
public User user;
public UserByToken userByToken;
public GenericContext(User user) {
public GenericContext(User user, UserByToken userByToken) {
this.user = user;
this.userByToken = userByToken;
}
@Override

View File

@ -2,6 +2,7 @@ package org.kar.archidata.filter;
import org.kar.archidata.model.User;
import org.kar.archidata.model.UserByToken;
import javax.ws.rs.core.SecurityContext;
import java.security.Principal;
@ -12,8 +13,8 @@ class MySecurityContext implements SecurityContext {
private final GenericContext contextPrincipale;
private final String sheme;
public MySecurityContext(User user, String sheme) {
this.contextPrincipale = new GenericContext(user);
public MySecurityContext(User user, UserByToken userByToken, String sheme) {
this.contextPrincipale = new GenericContext(user, userByToken);
this.sheme = sheme;
}
@ -24,24 +25,36 @@ class MySecurityContext implements SecurityContext {
@Override
public boolean isUserInRole(String role) {
if (role.contentEquals("ADMIN")) {
return contextPrincipale.user.admin == true;
}
if (role.contentEquals("USER")) {
// if not an admin, this is a user...
return true; //contextPrincipale.user.admin == false;
if (contextPrincipale.user != null) {
if (role.contentEquals("ADMIN")) {
return contextPrincipale.user.admin == true;
}
if (role.contentEquals("USER")) {
// if not an admin, this is a user...
return true; //contextPrincipale.user.admin == false;
}
}
if (contextPrincipale.userByToken != null) {
Boolean value = this.contextPrincipale.userByToken.right.get(role);
return value == true;
}
return false;
}
@Override
public boolean isSecure() {
return true;
return sheme.equalsIgnoreCase("https");
}
@Override
public String getAuthenticationScheme() {
return "Yota";
if (contextPrincipale.user != null) {
return "Yota";
}
if (contextPrincipale.userByToken != null) {
return "Zota";
}
return null;
}
}

View File

@ -26,12 +26,12 @@ public class GenericTable {
@SQLCreateTime
@SQLNotNull
@SQLComment("Create time of the object")
@SQLDefault("now()")
@SQLDefault("now(3)")
public Timestamp create_date = null;
@SQLNotRead
@SQLUpdateTime
@SQLNotNull
@SQLComment("When update the object")
@SQLDefault("now()")
@SQLDefault("now(3)")
public Timestamp modify_date = null;
}

View File

@ -0,0 +1,23 @@
package org.kar.archidata.model;
import java.sql.Timestamp;
import org.kar.archidata.annotation.SQLIfNotExists;
import org.kar.archidata.annotation.SQLNotNull;
import org.kar.archidata.annotation.SQLTableName;
import com.fasterxml.jackson.annotation.JsonInclude;
@SQLTableName ("applicationToken")
@SQLIfNotExists
@JsonInclude(JsonInclude.Include.NON_NULL)
public class GenericToken extends GenericTable {
@SQLNotNull
public Long parentId;
@SQLNotNull
public String name;
@SQLNotNull
public Timestamp endValidityTime = null;
@SQLNotNull
public String token;
}

View File

@ -3,16 +3,7 @@ package org.kar.archidata.model;
import java.sql.ResultSet;
import java.sql.SQLException;
/*
CREATE TABLE `token` (
`id` bigint NOT NULL COMMENT 'Unique ID of the TOKEN' AUTO_INCREMENT PRIMARY KEY,
`userId` bigint NOT NULL COMMENT 'Unique ID of the user',
`token` varchar(128) COLLATE 'latin1_bin' NOT NULL COMMENT 'Token (can be not unique)',
`createTime` datetime NOT NULL COMMENT 'Time the token has been created',
`endValidityTime` datetime NOT NULL COMMENT 'Time of the token end validity'
) AUTO_INCREMENT=10;
*/
public class Token {
public Long id;
public Long userId;

View File

@ -0,0 +1,19 @@
package org.kar.archidata.model;
import java.util.HashMap;
import java.util.Map;
public class UserByToken {
public static final int TYPE_USER = -1;
public static final int TYPE_APPLICATION = -2;
// application internal management type: an application generic Id
public Integer type = null;
public Long id = null;
public Long parentId = null;
public String name = null;
// Right map
public Map<String, Boolean> right = new HashMap<>();
}

View File

@ -10,6 +10,7 @@ public class ConfigBaseVariable {
static public String bdDatabase = System.getenv("DB_DATABASE");
static public String apiAdress = System.getenv("API_ADDRESS");
static public String ssoAdress = System.getenv("SSO_ADDRESS");
static public String ssoToken = System.getenv("SSO_TOKEN");
public static String getTmpDataFolder() {
if (tmpDataFolder == null) {
@ -74,4 +75,7 @@ public class ConfigBaseVariable {
}
return ssoAdress;
}
public static String ssoToken() {
return ssoToken;
}
}

View File

@ -46,6 +46,10 @@ public class JWTWrapper {
con.setRequestProperty("Cache-Control", "no-cache");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
String ssoToken = ConfigBaseVariable.ssoToken();
if (ssoToken != null) {
con.setRequestProperty("Authorization", "Zota " + ssoToken);
}
int responseCode = con.getResponseCode();
System.out.println("GET Response Code :: " + responseCode);
@ -95,12 +99,19 @@ public class JWTWrapper {
}
}
public static String getPublicKey() {
public static String getPublicKeyJson() {
if (rsaPublicJWK == null) {
return null;
}
return rsaPublicJWK.toJSONString();
}
public static java.security.interfaces.RSAPublicKey getPublicKeyJava() throws JOSEException {
if (rsaPublicJWK == null) {
return null;
}
// Convert back to std Java interface
return rsaPublicJWK.toRSAPublicKey();
}
/**
* Create a token with the provided elements