[DEV] rework authentication

This commit is contained in:
Edouard DUPIN 2023-04-22 00:32:29 +02:00
parent 12231762d3
commit dc8cae5150
10 changed files with 75 additions and 75 deletions

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.3.4</version>
<version>0.3.5</version>
<properties>
<jersey.version>3.1.1</jersey.version>
<jaxb.version>2.3.1</jaxb.version>

View File

@ -1,6 +1,4 @@
package org.kar.archidata;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MigrationSystem {

View File

@ -283,7 +283,7 @@ public class SqlWrapper {
// real add in the BDD:
try {
String tableName = getTableName(clazz);
boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
StringBuilder query = new StringBuilder();
query.append("INSERT INTO ");
query.append(tableName);
@ -455,7 +455,7 @@ public class SqlWrapper {
// real add in the BDD:
try {
String tableName = getTableName(clazz);
boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
StringBuilder query = new StringBuilder();
query.append("UPDATE ");
query.append(tableName);
@ -463,7 +463,6 @@ public class SqlWrapper {
boolean firstField = true;
Field primaryKeyField = null;
int count = 0;
for (Field elem : clazz.getFields()) {
boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0;
if (primaryKey) {
@ -489,7 +488,6 @@ public class SqlWrapper {
continue;
}
}
count++;
if (firstField) {
firstField = false;
} else {
@ -551,7 +549,6 @@ public class SqlWrapper {
ps.setString(iii++, dataTmp);
}
}
count++;
}
ps.setLong(iii++, id);
// execute the request
@ -693,6 +690,7 @@ public class SqlWrapper {
stmt.executeUpdate(querry);
}
@SuppressWarnings("unchecked")
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<>();
@ -774,7 +772,7 @@ public class SqlWrapper {
if (!full && createTime) {
continue;
}
String name = elem.getName();
//String name = elem.getName();
boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0;
if (!full && updateTime) {
continue;
@ -806,7 +804,7 @@ public class SqlWrapper {
}
}
if (primaryKeyField != null) {
return getWhere(clazz, primaryKeyField.getName(), "=", id);
return SqlWrapper.getWhere(clazz, List.of(new WhereCondition(primaryKeyField.getName(), "=", id)), false);
}
throw new Exception("Missing primary Key...");
}
@ -828,7 +826,7 @@ public class SqlWrapper {
// real add in the BDD:
try {
String tableName = getTableName(clazz);
boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
//boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0;
StringBuilder query = new StringBuilder();
query.append("SELECT ");
//query.append(tableName);
@ -985,7 +983,7 @@ public class SqlWrapper {
if (affectedRows == 0) {
throw new SQLException("Creating data failed, no rows affected.");
}
// retreive uid inserted
// retrieve uid inserted
try (ResultSet generatedKeys = ps.getGeneratedKeys()) {
if (generatedKeys.next()) {
uniqueSQLID = generatedKeys.getLong(1);
@ -1045,7 +1043,7 @@ public class SqlWrapper {
return out;
}
/**
* Convert the list if external Ids in a string '-' separated
* Convert the list if external id in a string '-' separated
* @param ids List of value (null are removed)
* @return '-' string separated
*/

View File

@ -229,7 +229,7 @@ public class DataResource {
public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
System.out.println("===================================================");
System.out.println("== DATA uploadFile " + (gc==null?"null":gc.user));
System.out.println("== DATA uploadFile " + (gc==null?"null":gc.userByToken));
System.out.println("===================================================");
//public NodeSmall uploadFile(final FormDataMultiPart form) {
System.out.println("Upload file: ");
@ -252,7 +252,7 @@ public class DataResource {
public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//System.out.println("===================================================");
System.out.println("== DATA retriveDataId ? id=" + id + " user=" + (gc==null?"null":gc.user));
System.out.println("== DATA retriveDataId ? id=" + id + " user=" + (gc==null?"null":gc.userByToken));
//System.out.println("===================================================");
Data value = getSmall(id);
if (value == null) {
@ -344,7 +344,7 @@ public class DataResource {
public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id, @PathParam("name") String name) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
//System.out.println("===================================================");
System.out.println("== DATA retriveDataFull ? id=" + id + " user=" + (gc==null?"null":gc.user));
System.out.println("== DATA retriveDataFull ? id=" + id + " user=" + (gc==null?"null":gc.userByToken));
//System.out.println("===================================================");
Data value = getSmall(id);
if (value == null) {

View File

@ -28,6 +28,7 @@ import com.nimbusds.jwt.JWTClaimsSet;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey
// https://stackoverflow.com/questions/26777083/best-practice-for-rest-token-based-authentication-with-jax-rs-and-jersey/45814178#45814178
@ -39,11 +40,19 @@ import java.util.Map.Entry;
public class AuthenticationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
protected final String applicationName;
private static final String AUTHENTICATION_SCHEME = "Yota";
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
@Override
public AuthenticationFilter(String applicationName) {
super();
this.applicationName = applicationName;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
/*
System.out.println("-----------------------------------------------------");
@ -95,38 +104,23 @@ public class AuthenticationFilter implements ContainerRequestFilter {
abortWithUnauthorized(requestContext);
return;
}
User user = null;
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);
userByToken = validateJwtToken(token);
} catch (Exception e) {
System.out.println("Fail to validate token: " + e.getMessage());
abortWithUnauthorized(requestContext);
return;
}
if (user == null) {
if (userByToken == 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();
@ -147,7 +141,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
// create the security context model:
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
MySecurityContext userContext = new MySecurityContext(user, userByToken, scheme);
MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
// retrieve the allowed right:
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
List<String> roles = Arrays.asList(rolesAnnotation.value());
@ -196,11 +190,11 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
protected UserByToken validateToken(String authorization) throws Exception {
System.out.println("dsfgsdgsdfgsdgf");
System.out.println("Must be Override by the application implmentation, otherwise it dose not work");
return null;
}
// must be override to be good implemenres
protected User validateJwtToken(String authorization) throws Exception {
// must be override to be good implementation
protected UserByToken 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...
@ -211,7 +205,21 @@ public class AuthenticationFilter implements ContainerRequestFilter {
// check userID
String userUID = ret.getSubject();
long id = Long.parseLong(userUID);
System.out.println("request user: '" + userUID + "'");
return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") );
UserByToken user = new UserByToken();
user.id = id;
user.name = (String)ret.getClaim("login");
user.type = UserByToken.TYPE_USER;
Object rowRight = ret.getClaim("right");
if (rowRight != null) {
Map<String, Map<String,Object>> rights = (Map<String, Map<String,Object>>) ret.getClaim("right");
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
System.out.println("Connect with no right for this application '" + this.applicationName + "' full Right='" + rights + "'");
}
}
System.out.println("request user: '" + userUID + "' right: '" + user.right + "' row='" +rowRight + "'");
return user;
//return UserDB.getUserOrCreate(id, (String)ret.getClaim("login") );
}
}

View File

@ -1,25 +1,22 @@
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, UserByToken userByToken) {
this.user = user;
public GenericContext(UserByToken userByToken) {
this.userByToken = userByToken;
}
@Override
public String getName() {
if (user == null) {
if (this.userByToken == null) {
return "???";
}
return user.login;
return this.userByToken.name;
}
}

View File

@ -1,7 +1,5 @@
package org.kar.archidata.filter;
import org.kar.archidata.model.User;
import org.kar.archidata.model.UserByToken;
import jakarta.ws.rs.core.SecurityContext;
@ -13,8 +11,8 @@ class MySecurityContext implements SecurityContext {
private final GenericContext contextPrincipale;
private final String sheme;
public MySecurityContext(User user, UserByToken userByToken, String sheme) {
this.contextPrincipale = new GenericContext(user, userByToken);
public MySecurityContext(UserByToken userByToken, String sheme) {
this.contextPrincipale = new GenericContext(userByToken);
this.sheme = sheme;
}
@ -25,18 +23,11 @@ class MySecurityContext implements SecurityContext {
@Override
public boolean isUserInRole(String role) {
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;
Object value = this.contextPrincipale.userByToken.right.get(role);
if (value instanceof Boolean ret) {
return ret;
}
}
return false;
}
@ -48,9 +39,6 @@ class MySecurityContext implements SecurityContext {
@Override
public String getAuthenticationScheme() {
if (contextPrincipale.user != null) {
return "Yota";
}
if (contextPrincipale.userByToken != null) {
return "Zota";
}

View File

@ -15,11 +15,14 @@ CREATE TABLE `user` (
*/
import java.sql.Timestamp;
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 com.fasterxml.jackson.annotation.JsonInclude;

View File

@ -11,9 +11,9 @@ public class UserByToken {
public Integer type = null;
public Long id = null;
public Long parentId = null;
public Long parentId = null; // FOr application, this is the id of the application, and of user token, this is the USERID
public String name = null;
// Right map
public Map<String, Boolean> right = new HashMap<>();
public Map<String, Object> right = new HashMap<>();
}

View File

@ -7,6 +7,8 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -72,11 +74,14 @@ public class JWTWrapper {
System.out.println("GET JWT validator token not worked");
}
public static void initLocalToken() throws Exception{
public static void initLocalToken(String baseUUID) throws Exception{
// RSA signatures require a public and private RSA key pair, the public key
// must be made known to the JWS recipient in order to verify the signatures
try {
String generatedStringForKey = UUID.randomUUID().toString();
String generatedStringForKey = baseUUID;
if (generatedStringForKey == null) {
generatedStringForKey = UUID.randomUUID().toString();
}
rsaJWK = new RSAKeyGenerator(2048).keyID(generatedStringForKey).generate();
rsaPublicJWK = rsaJWK.toPublicJWK();
//System.out.println("RSA key (all): " + rsaJWK.toJSONString());
@ -121,7 +126,7 @@ public class JWTWrapper {
* @param timeOutInMunites Expiration of the token.
* @return the encoded token
*/
public static String generateJWToken(long userID, String userLogin, String isuer, String application, int timeOutInMunites) {
public static String generateJWToken(long userID, String userLogin, String isuer, String application, Map<String, Object> rights, int timeOutInMunites) {
if (rsaJWK == null) {
System.out.println("JWT private key is not present !!!");
return null;
@ -134,17 +139,20 @@ public class JWTWrapper {
*/
try {
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);
// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
JWSSigner signer = new RSASSASigner(rsaJWK);
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder()
.subject(Long.toString(userID))
.claim("login", userLogin)
.claim("application", application)
.issuer(isuer)
.issueTime(new Date())
.expirationTime(new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */)) // Do not ask why we need a "-" here ... this have no meaning
.build();
.expirationTime(new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */)); // Do not ask why we need a "-" here ... this have no meaning
// add right if needed:
if (rights != null && !rights.isEmpty()) {
builder.claim("right", rights);
}
// Prepare JWT with claims set
JWTClaimsSet claimsSet = builder.build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
// Compute the RSA signature