diff --git a/pom.xml b/pom.xml
index f353996..0e89f4b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
kangaroo-and-rabbit
archidata
- 0.2.6
+ 0.3.1
2.1
2.32
diff --git a/src/org/kar/archidata/MigrationAction.java b/src/org/kar/archidata/MigrationAction.java
new file mode 100644
index 0000000..61d8495
--- /dev/null
+++ b/src/org/kar/archidata/MigrationAction.java
@@ -0,0 +1,5 @@
+package org.kar.archidata;
+
+public class MigrationAction {
+
+}
diff --git a/src/org/kar/archidata/SqlWrapper.java b/src/org/kar/archidata/SqlWrapper.java
index dae1b4c..eec4080 100644
--- a/src/org/kar/archidata/SqlWrapper.java
+++ b/src/org/kar/archidata/SqlWrapper.java
@@ -616,6 +616,45 @@ public class SqlWrapper {
public static List getsWhere(Class clazz, List condition, boolean full, Integer linit) throws Exception {
return getsWhere(clazz, condition, null, full, linit);
}
+ public static void whereAppendQuery(StringBuilder query, String tableName, List 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 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 List getsWhere(Class clazz, List condition, String orderBy, boolean full, Integer linit) throws Exception {
DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig);
List 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 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 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();
}
+
}
\ No newline at end of file
diff --git a/src/org/kar/archidata/filter/AuthenticationFilter.java b/src/org/kar/archidata/filter/AuthenticationFilter.java
index 7ac1e2b..c8af819 100644
--- a/src/org/kar/archidata/filter/AuthenticationFilter.java
+++ b/src/org/kar/archidata/filter/AuthenticationFilter.java
@@ -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 pathparam = requestContext.getUriInfo().getPathParameters();
- for (Entry> 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 quaryparam = requestContext.getUriInfo().getQueryParameters();
- for (Entry> item: quaryparam.entrySet()) {
- System.out.println(" query: " + item.getKey() + " ==>" + item.getValue());
- }
- System.out.println(" -------------------------------");
- List segments = requestContext.getUriInfo().getPathSegments();
- for (final PathSegment item: segments) {
- System.out.println(" query: " + item.getPath() + " ==>" + item.getMatrixParameters());
- }
- System.out.println(" -------------------------------");
- MultivaluedMap headers = requestContext.getHeaders();
- for (Entry> 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 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...
diff --git a/src/org/kar/archidata/filter/GenericContext.java b/src/org/kar/archidata/filter/GenericContext.java
index faeb5c9..a45c19b 100644
--- a/src/org/kar/archidata/filter/GenericContext.java
+++ b/src/org/kar/archidata/filter/GenericContext.java
@@ -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
diff --git a/src/org/kar/archidata/filter/MySecurityContext.java b/src/org/kar/archidata/filter/MySecurityContext.java
index b61a564..7dcdcb2 100644
--- a/src/org/kar/archidata/filter/MySecurityContext.java
+++ b/src/org/kar/archidata/filter/MySecurityContext.java
@@ -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;
}
}
\ No newline at end of file
diff --git a/src/org/kar/archidata/model/GenericTable.java b/src/org/kar/archidata/model/GenericTable.java
index 41ab29c..e4b1e19 100644
--- a/src/org/kar/archidata/model/GenericTable.java
+++ b/src/org/kar/archidata/model/GenericTable.java
@@ -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;
}
diff --git a/src/org/kar/archidata/model/GenericToken.java b/src/org/kar/archidata/model/GenericToken.java
new file mode 100644
index 0000000..5f6195d
--- /dev/null
+++ b/src/org/kar/archidata/model/GenericToken.java
@@ -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;
+}
diff --git a/src/org/kar/archidata/model/Token.java b/src/org/kar/archidata/model/Token.java
index 636cbfd..61f1ae6 100644
--- a/src/org/kar/archidata/model/Token.java
+++ b/src/org/kar/archidata/model/Token.java
@@ -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;
diff --git a/src/org/kar/archidata/model/UserByToken.java b/src/org/kar/archidata/model/UserByToken.java
new file mode 100644
index 0000000..d2abc6a
--- /dev/null
+++ b/src/org/kar/archidata/model/UserByToken.java
@@ -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 right = new HashMap<>();
+
+}
diff --git a/src/org/kar/archidata/util/ConfigBaseVariable.java b/src/org/kar/archidata/util/ConfigBaseVariable.java
index 6501e17..4ce11b1 100644
--- a/src/org/kar/archidata/util/ConfigBaseVariable.java
+++ b/src/org/kar/archidata/util/ConfigBaseVariable.java
@@ -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;
+ }
}
diff --git a/src/org/kar/archidata/util/JWTWrapper.java b/src/org/kar/archidata/util/JWTWrapper.java
index 2b9452e..d941cf7 100644
--- a/src/org/kar/archidata/util/JWTWrapper.java
+++ b/src/org/kar/archidata/util/JWTWrapper.java
@@ -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