From 09ff403d9a894de9720aceb1c34c6b5d1c72a3ac Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 7 Nov 2022 00:28:34 +0100 Subject: [PATCH] [DEV] extarct maximul from karauth and karusic --- .classpath | 27 + .project | 23 + CheckStyle.xml | 66 + CleanUp.xml | 66 + Formatter.xml | 366 +++++ LICENSE | 6 + pom.xml | 177 +++ .../kar/archidata/GlobalConfiguration.java | 16 + src/org/kar/archidata/SqlWrapper.java | 1205 +++++++++++++++++ src/org/kar/archidata/UpdateJwtPublicKey.java | 34 + src/org/kar/archidata/UserDB.java | 133 ++ .../annotation/PermitTokenInURI.java | 15 + .../annotation/SQLAutoIncrement.java | 12 + .../kar/archidata/annotation/SQLComment.java | 14 + .../archidata/annotation/SQLCreateTime.java | 12 + .../kar/archidata/annotation/SQLDefault.java | 14 + .../archidata/annotation/SQLIfNotExists.java | 12 + .../archidata/annotation/SQLLimitSize.java | 12 + .../kar/archidata/annotation/SQLNotNull.java | 12 + .../kar/archidata/annotation/SQLNotRead.java | 12 + .../archidata/annotation/SQLPrimaryKey.java | 12 + .../annotation/SQLTableLinkGeneric.java | 20 + .../archidata/annotation/SQLTableName.java | 14 + .../archidata/annotation/SQLUpdateTime.java | 12 + src/org/kar/archidata/api/FrontGeneric.java | 104 ++ src/org/kar/archidata/db/DBConfig.java | 60 + src/org/kar/archidata/db/DBEntry.java | 45 + .../filter/AuthenticationFilter.java | 198 +++ src/org/kar/archidata/filter/CORSFilter.java | 25 + .../kar/archidata/filter/GenericContext.java | 22 + .../archidata/filter/MySecurityContext.java | 47 + .../kar/archidata/filter/OptionFilter.java | 21 + src/org/kar/archidata/internal/Log.java | 60 + src/org/kar/archidata/model/Data.java | 32 + src/org/kar/archidata/model/GenericTable.java | 35 + src/org/kar/archidata/model/State.java | 12 + src/org/kar/archidata/model/Token.java | 57 + src/org/kar/archidata/model/User.java | 53 + src/org/kar/archidata/model/UserExtern.java | 36 + src/org/kar/archidata/model/UserPerso.java | 42 + src/org/kar/archidata/model/UserSmall.java | 73 + .../archidata/util/ConfigBaseVariable.java | 78 ++ src/org/kar/archidata/util/DataTools.java | 346 +++++ src/org/kar/archidata/util/JWTWrapper.java | 175 +++ src/org/kar/archidata/util/PublicKey.java | 10 + 45 files changed, 3823 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100755 CheckStyle.xml create mode 100644 CleanUp.xml create mode 100644 Formatter.xml create mode 100644 LICENSE create mode 100644 pom.xml create mode 100644 src/org/kar/archidata/GlobalConfiguration.java create mode 100644 src/org/kar/archidata/SqlWrapper.java create mode 100644 src/org/kar/archidata/UpdateJwtPublicKey.java create mode 100755 src/org/kar/archidata/UserDB.java create mode 100644 src/org/kar/archidata/annotation/PermitTokenInURI.java create mode 100644 src/org/kar/archidata/annotation/SQLAutoIncrement.java create mode 100644 src/org/kar/archidata/annotation/SQLComment.java create mode 100644 src/org/kar/archidata/annotation/SQLCreateTime.java create mode 100644 src/org/kar/archidata/annotation/SQLDefault.java create mode 100644 src/org/kar/archidata/annotation/SQLIfNotExists.java create mode 100644 src/org/kar/archidata/annotation/SQLLimitSize.java create mode 100644 src/org/kar/archidata/annotation/SQLNotNull.java create mode 100644 src/org/kar/archidata/annotation/SQLNotRead.java create mode 100644 src/org/kar/archidata/annotation/SQLPrimaryKey.java create mode 100644 src/org/kar/archidata/annotation/SQLTableLinkGeneric.java create mode 100644 src/org/kar/archidata/annotation/SQLTableName.java create mode 100644 src/org/kar/archidata/annotation/SQLUpdateTime.java create mode 100644 src/org/kar/archidata/api/FrontGeneric.java create mode 100644 src/org/kar/archidata/db/DBConfig.java create mode 100644 src/org/kar/archidata/db/DBEntry.java create mode 100644 src/org/kar/archidata/filter/AuthenticationFilter.java create mode 100644 src/org/kar/archidata/filter/CORSFilter.java create mode 100644 src/org/kar/archidata/filter/GenericContext.java create mode 100644 src/org/kar/archidata/filter/MySecurityContext.java create mode 100644 src/org/kar/archidata/filter/OptionFilter.java create mode 100644 src/org/kar/archidata/internal/Log.java create mode 100644 src/org/kar/archidata/model/Data.java create mode 100644 src/org/kar/archidata/model/GenericTable.java create mode 100644 src/org/kar/archidata/model/State.java create mode 100644 src/org/kar/archidata/model/Token.java create mode 100644 src/org/kar/archidata/model/User.java create mode 100644 src/org/kar/archidata/model/UserExtern.java create mode 100644 src/org/kar/archidata/model/UserPerso.java create mode 100644 src/org/kar/archidata/model/UserSmall.java create mode 100644 src/org/kar/archidata/util/ConfigBaseVariable.java create mode 100644 src/org/kar/archidata/util/DataTools.java create mode 100644 src/org/kar/archidata/util/JWTWrapper.java create mode 100644 src/org/kar/archidata/util/PublicKey.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..3bf4578 --- /dev/null +++ b/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..c4e3f9b --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + achi-data + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/CheckStyle.xml b/CheckStyle.xml new file mode 100755 index 0000000..d68aedd --- /dev/null +++ b/CheckStyle.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CleanUp.xml b/CleanUp.xml new file mode 100644 index 0000000..9df98d2 --- /dev/null +++ b/CleanUp.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Formatter.xml b/Formatter.xml new file mode 100644 index 0000000..b775e22 --- /dev/null +++ b/Formatter.xml @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a9d1e81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,6 @@ +PROPIETARY licence +================== + +Copyright at Edouard DUPIN + +you have no right \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..54d39e2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,177 @@ + + 4.0.0 + kar + archidata + 0.1.0 + + 2.1 + 2.32 + 2.3.1 + 3.0.7 + + 3.1 + 17 + 17 + + 3.1.1 + + + + + + + org.glassfish.jersey + jersey-bom + ${jersey.version} + pom + import + + + + + + + + org.glassfish.jersey.media + jersey-media-multipart + + + org.glassfish.jersey.inject + jersey-hk2 + + + org.glassfish.jersey.containers + jersey-container-grizzly2-http + + + javax.xml.bind + jaxb-api + ${jaxb.version} + + + javax.ws.rs + javax.ws.rs-api + 2.1.1 + + + com.sun.xml.bind + jaxb-impl + ${jaxb.version} + + + com.sun.istack + istack-commons-runtime + ${istack.version} + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-grizzly2 + test + + + mysql + mysql-connector-java + 8.0.30 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + com.fasterxml.jackson.core + jackson-databind + 2.8.10 + + + javax.servlet + javax.servlet-api + 3.0.1 + compile + + + org.jetbrains + annotations + RELEASE + compile + + + com.nimbusds + nimbus-jose-jwt + 9.22 + + + + + src + test/src + ${project.basedir}/out/maven/ + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.version} + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + + maven-assembly-plugin + + + + fully.qualified.MainClass + + + + jar-with-dependencies + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + private + true + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + public + + + + + + \ No newline at end of file diff --git a/src/org/kar/archidata/GlobalConfiguration.java b/src/org/kar/archidata/GlobalConfiguration.java new file mode 100644 index 0000000..7e18866 --- /dev/null +++ b/src/org/kar/archidata/GlobalConfiguration.java @@ -0,0 +1,16 @@ +package org.kar.archidata; + +import org.kar.archidata.db.DBConfig; +import org.kar.archidata.util.ConfigBaseVariable; + +public class GlobalConfiguration { + public static DBConfig dbConfig = null;; + + static { + dbConfig = new DBConfig(ConfigBaseVariable.getDBHost(), + Integer.parseInt(ConfigBaseVariable.getDBPort()), + ConfigBaseVariable.getDBLogin(), + ConfigBaseVariable.getDBPassword(), + ConfigBaseVariable.getDBName()); + } +} diff --git a/src/org/kar/archidata/SqlWrapper.java b/src/org/kar/archidata/SqlWrapper.java new file mode 100644 index 0000000..5aafed9 --- /dev/null +++ b/src/org/kar/archidata/SqlWrapper.java @@ -0,0 +1,1205 @@ +package org.kar.archidata; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.sql.*; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLIfNotExists; +import org.kar.archidata.annotation.SQLLimitSize; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableLinkGeneric; +import org.kar.archidata.annotation.SQLTableLinkGeneric.ModelLink; +import org.kar.archidata.annotation.SQLTableName; +import org.kar.archidata.annotation.SQLUpdateTime; +import org.kar.archidata.db.DBEntry; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.kar.archidata.annotation.SQLCreateTime; +import org.kar.archidata.annotation.SQLDefault; + + +public class SqlWrapper { + + public static class ExceptionDBInterface extends Exception { + public int errorID; + ExceptionDBInterface(int errorId, String message) { + super(message); + this.errorID = errorId; + } + } + + public SqlWrapper() { + + } + + public static String convertTypeInSQL(Class type) throws Exception { + if (type == Long.class || type == long.class ) { + return "bigint"; + } + if (type == Integer.class || type == int.class ) { + return "int"; + } + if (type == Boolean.class || type == boolean.class) { + return "tinyint(1)"; + } + if (type == Float.class || type == float.class) { + return "float"; + } + if (type == Double.class || type == double.class) { + return "double"; + } + if (type == Timestamp.class) { + return "timestamp(3)"; + } + if (type == Date.class) { + return "date"; + } + if (type == String.class) { + return "text"; + } + throw new Exception("Imcompatible type of element in object for: " + type.getCanonicalName()); + } + + protected static void setValuedb(Class type, T data, int index, Field field, PreparedStatement ps) throws IllegalArgumentException, IllegalAccessException, SQLException { + if (type == Long.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.BIGINT); + } else { + ps.setLong(index++, (Long)tmp); + } + } else if (type == long.class ) { + ps.setLong(index++, field.getLong(data)); + } else if (type == Integer.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setInt(index++, (Integer)tmp); + } + } else if (type == int.class ) { + ps.setInt(index++, field.getInt(data)); + } else if (type == Float.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.FLOAT); + } else { + ps.setFloat(index++, (Float)tmp); + } + } else if (type == float.class) { + ps.setFloat(index++, field.getFloat(data)); + } else if (type == Double.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.DOUBLE); + } else { + ps.setDouble(index++, (Double)tmp); + } + } else if (type == Double.class) { + ps.setDouble(index++, field.getDouble(data)); + } else if (type == Boolean.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setBoolean(index++, (Boolean)tmp); + } + } else if (type == boolean.class) { + ps.setBoolean(index++, field.getBoolean(data)); + } else if (type == Timestamp.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setTimestamp(index++, (Timestamp)tmp); + } + } else if (type == Date.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.INTEGER); + } else { + ps.setDate(index++, (Date)tmp); + } + } else if (type == String.class) { + Object tmp = field.get(data); + if (tmp == null) { + ps.setNull(index++, Types.VARCHAR); + } else { + ps.setString(index++, (String)tmp); + } + } + } + protected static void setValueFromDb(Class type, T data, int index, Field field, ResultSet rs) throws IllegalArgumentException, IllegalAccessException, SQLException { + if (type == Long.class) { + Long tmp = rs.getLong(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + //System.out.println(" ==> " + tmp); + field.set(data, tmp); + } + } else if (type == long.class ) { + Long tmp = rs.getLong(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setLong(data, tmp); + } + } else if (type == Integer.class) { + Integer tmp = rs.getInt(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == int.class ) { + Integer tmp = rs.getInt(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setInt(data, tmp); + } + } else if (type == Float.class) { + Float tmp = rs.getFloat(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == float.class) { + Float tmp = rs.getFloat(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setFloat(data, tmp); + } + } else if (type == Double.class) { + Double tmp = rs.getDouble(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == double.class) { + Double tmp = rs.getDouble(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setDouble(data, tmp); + } + } else if (type == Boolean.class) { + Boolean tmp = rs.getBoolean(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == boolean.class) { + Boolean tmp = rs.getBoolean(index); + if (rs.wasNull()) { + //field.set(data, null); + } else { + field.setBoolean(data, tmp); + } + } else if (type == Timestamp.class) { + Timestamp tmp = rs.getTimestamp(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == Date.class) { + Date tmp = rs.getDate(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } else if (type == String.class) { + String tmp = rs.getString(index); + if (rs.wasNull()) { + field.set(data, null); + } else { + field.set(data, tmp); + } + } + } + public static ModelLink getLinkMode(Field elem) { + SQLTableLinkGeneric[] decorators = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class); + if (decorators == null || decorators.length == 0) { + return SQLTableLinkGeneric.ModelLink.NONE; + } + return decorators[0].value(); + } + + public static T insert(T data) throws Exception { + Class clazz = data.getClass(); + //public static NodeSmall createNode(String typeInNode, String name, String descrition, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("INSERT INTO "); + query.append(tableName); + query.append(" ("); + + boolean firstField = true; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + if (!elem.getClass().isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + count++; + String name = elem.getName(); + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("`"); + } + firstField = true; + query.append(") VALUES ("); + for (int iii = 0; iii type = elem.getType(); + if (!type.isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii++, elem, ps); + } else { + // transform the data in string to insert it ... + Object tmp = elem.get(data); + if (tmp == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + String dataTmp = getStringOfIds((List)tmp); + ps.setString(iii++, dataTmp); + } + } + count++; + } + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating node failed, no rows affected."); + } + Long uniqueSQLID = null; + // retreive uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating node failed, no ID obtained (1)."); + } + } catch (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating node failed, no ID obtained (2)."); + } + if (primaryKeyField != null) { + if (primaryKeyField.getType() == Long.class) { + primaryKeyField.set(data, (Long)uniqueSQLID); + } else if (primaryKeyField.getType() == long.class) { + primaryKeyField.setLong(data, uniqueSQLID); + } else { + System.out.println("Can not manage the primary filed !!!"); + } + } + //ps.execute(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + return data; + } + + public static T insertWithJson(Class clazz, String jsonData) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + T data = mapper.readValue(jsonData, clazz); + return insert(data); + } + + public static void update(Class clazz, long id, String jsonData) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + // parse the object to be sure the data are valid: + T data = mapper.readValue(jsonData, clazz); + // Read the tree to filter injection of data: + JsonNode root = mapper.readTree(jsonData); + List keys = new ArrayList<>(); + Iterator iterator = root.fieldNames(); + iterator.forEachRemaining(e -> keys.add(e)); + update(data, id, keys); + } + + public static void update(T data, long id, List filterValue) throws Exception { + Class clazz = data.getClass(); + //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("UPDATE "); + query.append(tableName); + query.append(" SET "); + + boolean firstField = true; + Field primaryKeyField = null; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (! updateTime && !filterValue.contains(name)) { + continue; + } + if (!elem.getClass().isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" `"); + query.append(name); + query.append("` = "); + if (updateTime) { + query.append(" now(3) "); + } else { + query.append("? "); + } + } + query.append(" WHERE `"); + query.append(primaryKeyField.getName()); + query.append("` = ?"); + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + continue; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime || !filterValue.contains(name)) { + continue; + } + if (linkGeneric == ModelLink.NONE) { + Class type = elem.getType(); + if (!type.isPrimitive()) { + Object tmp = elem.get(data); + if(tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + continue; + } + } + setValuedb(type, data, iii++, elem, ps); + } else { + // transform the data in string to insert it ... + Object tmp = elem.get(data); + if (tmp == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + String dataTmp = getStringOfIds((List)tmp); + ps.setString(iii++, dataTmp); + } + } + count++; + } + ps.setLong(iii++, id); + // execute the request + int affectedRows = ps.executeUpdate(); + // todo manage the list of element is valid ... + //ps.execute(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + + public static T getWith(Class clazz, String key, String value) throws Exception { + //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + T out = null; + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + Field primaryKeyField = null; + int count = 0; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" "); + query.append(tableName); + query.append("."); + query.append(name); + } + query.append("\n FROM `"); + query.append(tableName); + query.append("` "); + query.append("\n WHERE "); + query.append(tableName); + query.append("."); + query.append(key); + query.append(" = ?"); + query.append("\n LIMIT 1 "); + /* + query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + */ + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setString(iii++, value); + // execute the request + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + //this.name = rs.getString(iii++); + //this.description = rs.getString(iii++); + //this.covers = getListOfIds(rs, iii++); + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + out = (T)data; + } + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static T getWhere(Class clazz, String key, String operator, Object value ) throws Exception { + + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + T out = null; + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + int count = 0; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + query.append(" "); + query.append(tableName); + query.append("."); + + query.append(name); + } + query.append(" FROM `"); + query.append(tableName); + query.append("` "); + query.append(" WHERE "); + query.append(tableName); + query.append("."); + query.append(key); + query.append(" "); + query.append(operator); + query.append(" ?"); + /* + query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + */ + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + int iii = 1; + if (value.getClass() == Long.class) { + ps.setLong(iii++, (Long)value); + } else if (value.getClass() == Integer.class) { + ps.setInt(iii++, (Integer)value); + } else if (value.getClass() == String.class) { + ps.setString(iii++, (String)value); + } else if (value.getClass() == Short.class) { + ps.setShort(iii++, (Short)value); + } else if (value.getClass() == Byte.class) { + ps.setByte(iii++, (Byte)value); + } else { + throw new Exception("Not manage type ==> need to add it ..."); + } + // execute the request + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric != ModelLink.NONE) { + continue; + } + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + if (createTime) { + continue; + } + String name = elem.getName(); + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + if (updateTime) { + continue; + } + //this.name = rs.getString(iii++); + //this.description = rs.getString(iii++); + //this.covers = getListOfIds(rs, iii++); + setValueFromDb(elem.getType(), data, count, elem, rs); + count++; + } + out = (T)data; + } + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static T get(Class clazz, long id) throws Exception { + Field primaryKeyField = null; + for (Field elem : clazz.getFields()) { + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + if (primaryKey) { + primaryKeyField = elem; + } + } + if (primaryKeyField != null) { + return getWhere(clazz, primaryKeyField.getName(), "=", id); + } + throw new Exception("Missing primary Key..."); + } + + private enum StateLoad { + DISABLE, + NORMAL, + ARRAY + }; + + public static String getCurrentTimeStamp() { + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")); + } + + public static List gets(Class clazz, boolean fool) throws Exception { + System.out.println("request get " + clazz.getCanonicalName() + " start @" + getCurrentTimeStamp()); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + List out = new ArrayList<>(); + // real add in the BDD: + try { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder query = new StringBuilder(); + query.append("SELECT "); + //query.append(tableName); + //query.append(" SET "); + + boolean firstField = true; + int count = 0; + StateLoad[] autoClasify = new StateLoad[clazz.getFields().length]; + int indexAutoClasify = 0; + for (Field elem : clazz.getFields()) { + + boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + if (!fool && notRead) { + autoClasify[indexAutoClasify++] = StateLoad.DISABLE; + continue; + } + String name = elem.getName(); + count++; + if (firstField) { + firstField = false; + } else { + query.append(","); + } + ModelLink linkGeneric = getLinkMode(elem); + if (linkGeneric == ModelLink.EXTERNAL) { + autoClasify[indexAutoClasify++] = StateLoad.ARRAY; + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length()-1); + } + String tmpVariable = "tmp_" + Integer.toString(count); + query.append(" (SELECT GROUP_CONCAT("); + query.append(tmpVariable); + query.append("."); + query.append(localName); + query.append("_id SEPARATOR '-') FROM "); + query.append(tableName); + query.append("_link_"); + query.append(localName); + query.append(" "); + query.append(tmpVariable); + query.append(" WHERE "); + query.append(tmpVariable); + query.append(".deleted = false AND "); + query.append(tableName); + query.append(".id = "); + query.append(tmpVariable); + query.append("."); + query.append(tableName); + query.append("_id GROUP BY "); + query.append(tmpVariable); + query.append("."); + query.append(tableName); + query.append("_id ) AS "); + query.append(name); + query.append(" "); + /* + " (SELECT GROUP_CONCAT(tmp.data_id SEPARATOR '-')" + + " FROM cover_link_node tmp" + + " WHERE tmp.deleted = false" + + " AND node.id = tmp.node_id" + + " GROUP BY tmp.node_id) AS covers" + + */ + } else { + if (linkGeneric == ModelLink.NONE) { + autoClasify[indexAutoClasify++] = StateLoad.NORMAL; + } else { + autoClasify[indexAutoClasify++] = StateLoad.ARRAY; + } + query.append(" "); + query.append(tableName); + query.append("."); + query.append(name); + } + } + query.append(" FROM `"); + query.append(tableName); + query.append("` "); + query.append(" WHERE "); + //query.append(tableName); + //query.append("."); + //query.append(primaryKeyField.getName()); + //query.append(" = ?"); + //query.append(" AND "); + query.append(tableName); + query.append(".deleted = false "); + firstField = true; + System.out.println("generate the querry: '" + query.toString() + "'"); + System.out.println("request get " + clazz.getCanonicalName() + " prepare @" + getCurrentTimeStamp()); + // prepare the request: + PreparedStatement ps = entry.connection.prepareStatement(query.toString(), Statement.RETURN_GENERATED_KEYS); + + System.out.println("request get " + clazz.getCanonicalName() + " query @" + getCurrentTimeStamp()); + // execute the request + ResultSet rs = ps.executeQuery(); + System.out.println("request get " + clazz.getCanonicalName() + " transform @" + getCurrentTimeStamp()); + + while (rs.next()) { + indexAutoClasify = 0; + Object data = clazz.getConstructors()[0].newInstance(); + count = 1; + for (Field elem : clazz.getFields()) { + /* + boolean notRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + */ + boolean notRead = autoClasify[indexAutoClasify] == StateLoad.DISABLE; + if (!fool && notRead) { + indexAutoClasify++; + continue; + } + //String name = elem.getName(); + //boolean linkGeneric = elem.getDeclaredAnnotationsByType(SQLTableLinkGeneric.class).length != 0; + boolean linkGeneric = autoClasify[indexAutoClasify] == StateLoad.ARRAY; + if (linkGeneric) { + List idList = getListOfIds(rs, count); + elem.set(data, idList); + } else { + setValueFromDb(elem.getType(), data, count, elem, rs); + } + indexAutoClasify++; + count++; + } + //System.out.println("Read: " + (T)data); + out.add((T)data); + } + + System.out.println("request get " + clazz.getCanonicalName() + " ready @" + getCurrentTimeStamp()); + + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + entry = null; + return out; + } + + public static void addLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + // real add in the BDD: + try { + // prepare the request: + String query = "INSERT INTO " + tableName + "_link_" + table + " (create_date, modify_date, " + tableName + "_id, " + table + "_id)" + + " VALUES (now(3), now(3), ?, ?)"; + PreparedStatement ps = entry.connection.prepareStatement(query, + Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating data failed, no rows affected."); + } + // retreive uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating user failed, no ID obtained (1)."); + } + } catch (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating user failed, no ID obtained (2)."); + } + } catch (SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.disconnect(); + } + } + public static void removeLink(Class clazz, long localKey, String table, long remoteKey) throws Exception { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `" + tableName + "_link_" + table + "` SET `modify_date`=now(3), `deleted`=true WHERE `" + tableName + "_id` = ? AND `" + table + "_id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + int iii = 1; + ps.setLong(iii++, localKey); + ps.setLong(iii++, remoteKey); + ps.executeUpdate(); + } catch (SQLException ex) { + ex.printStackTrace(); + throw new ExceptionDBInterface(500, "SQL error: " + ex.getMessage()); + } finally { + entry.disconnect(); + } + } + + /** + * extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. + */ + protected static List getListOfIds(ResultSet rs, int iii) throws SQLException { + String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + List out = new ArrayList<>(); + String[] elements = trackString.split("-"); + for (String elem : elements) { + Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + /** + * Convert the list if external Ids in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated + */ + protected static String getStringOfIds(List ids) { + List tmp = new ArrayList<>(); + for (Long elem : ids) { + tmp.add(elem); + } + return tmp.stream().map(x->String.valueOf(x)).collect(Collectors.joining("-")); + } + + + 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 { + String tableName = getTableName(clazz); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `" + tableName + "` SET `modify_date`=now(3), `deleted`=true WHERE `id` = ?"; + 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()); + } finally { + entry.disconnect(); + } + } + + public static String createTable(Class clazz) throws Exception { + String tableName = getTableName(clazz); + boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + StringBuilder out = new StringBuilder(); + StringBuilder otherTable = new StringBuilder(); + // Drop Table + if (createIfNotExist) { + out.append("DROP TABLE IF EXISTS `"); + out.append(tableName); + out.append("`;\n"); + } + // create Table: + out.append("CREATE TABLE `"); + out.append(tableName); + out.append("` ("); + boolean firstField = true; + System.out.println("===> TABLE `" + tableName + "`"); + String primaryKeyValue = null; + for (Field elem : clazz.getFields()) { + + String name = elem.getName(); + Integer limitSize = getLimitSize(elem); + boolean notNull = elem.getDeclaredAnnotationsByType(SQLNotNull.class).length != 0; + boolean autoIncrement = elem.getDeclaredAnnotationsByType(SQLAutoIncrement.class).length != 0; + + boolean primaryKey = elem.getDeclaredAnnotationsByType(SQLPrimaryKey.class).length != 0; + //boolean sqlNotRead = elem.getDeclaredAnnotationsByType(SQLNotRead.class).length != 0; + boolean createTime = elem.getDeclaredAnnotationsByType(SQLCreateTime.class).length != 0; + boolean updateTime = elem.getDeclaredAnnotationsByType(SQLUpdateTime.class).length != 0; + ModelLink linkGeneric = getLinkMode(elem); + String comment = getComment(elem); + String defaultValue = getDefault(elem); + //System.out.println(" ==> elem `" + name + "` primaryKey=" + primaryKey + " linkGeneric=" + linkGeneric); + + + if (primaryKey) { + primaryKeyValue = name; + } + // special case with external link table: + if (linkGeneric == ModelLink.EXTERNAL) { + String localName = name; + if (name.endsWith("s")) { + localName = name.substring(0, name.length()-1); + } + if (createIfNotExist) { + otherTable.append("DROP TABLE IF EXISTS `"); + otherTable.append(tableName); + otherTable.append("_link_"); + otherTable.append(localName); + otherTable.append("`;\n"); + } + otherTable.append("CREATE TABLE `"); + otherTable.append(tableName); + otherTable.append("_link_"); + otherTable.append(localName); + otherTable.append("`(\n"); + otherTable.append("\t\t`id` bigint NOT NULL AUTO_INCREMENT,\n"); + otherTable.append("\t\t`deleted` tinyint(1) NOT NULL DEFAULT '0',\n"); + otherTable.append("\t\t`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); + otherTable.append("\t\t`modify_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),\n"); + otherTable.append("\t\t`"); + otherTable.append(tableName); + otherTable.append("_id` bigint NOT NULL,\n"); + otherTable.append("\t\t`"); + otherTable.append(localName); + otherTable.append("_id` bigint NOT NULL,\n"); + otherTable.append("\tPRIMARY KEY (`id`)\n"); + otherTable.append("\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n\n"); + } else { + if (firstField) { + out.append("\n\t\t`"); + firstField = false; + } else { + out.append(",\n\t\t`"); + } + out.append(name); + out.append("` "); + String typeValue = null; + if (linkGeneric == ModelLink.INTERNAL) { + typeValue = convertTypeInSQL(String.class); + out.append(typeValue); + } else { + typeValue = convertTypeInSQL(elem.getType()); + if (typeValue.equals("text")) { + if (limitSize != null) { + out.append("varchar("); + out.append(limitSize); + out.append(")"); + } else { + out.append("text CHARACTER SET utf8"); + } + } else { + out.append(typeValue); + } + } + out.append(" "); + if (notNull) { + out.append("NOT NULL "); + if (defaultValue == null) { + if (updateTime || createTime) { + out.append("DEFAULT CURRENT_TIMESTAMP(3) "); + } + } else { + out.append("DEFAULT "); + out.append(defaultValue); + out.append(" "); + } + } else if (defaultValue == null) { + if (updateTime || createTime) { + out.append("DEFAULT CURRENT_TIMESTAMP(3) "); + } else { + out.append("DEFAULT NULL "); + } + } else { + out.append("DEFAULT "); + out.append(defaultValue); + out.append(" "); + + } + if (autoIncrement) { + out.append("AUTO_INCREMENT "); + } + + if (comment != null) { + out.append("COMMENT '"); + out.append(comment.replaceAll("'", "\'")); + out.append("' "); + } + } + } + if (primaryKeyValue != null) { + out.append(",\n\tPRIMARY KEY (`"); + out.append(primaryKeyValue); + out.append("`)"); + } + out.append("\n\t) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\n"); + return out.toString() + otherTable.toString(); + } + + + public static String getTableName(final Class element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLTableName.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLTableName) annotation[0]).value(); + if (tmp == null) { + return null; + } + return tmp; + } + public static String getComment(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLComment.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLComment) annotation[0]).value(); + if (tmp == null) { + return null; + } + return tmp; + } + public static String getDefault(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLDefault.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + final String tmp = ((SQLDefault) annotation[0]).value(); + if (tmp == null) { + return null; + } + return tmp; + } + public static Integer getLimitSize(final Field element) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(SQLLimitSize.class); + if (annotation.length == 0) { + return null; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); + } + return ((SQLLimitSize) annotation[0]).value(); + } + +} \ No newline at end of file diff --git a/src/org/kar/archidata/UpdateJwtPublicKey.java b/src/org/kar/archidata/UpdateJwtPublicKey.java new file mode 100644 index 0000000..a8e0594 --- /dev/null +++ b/src/org/kar/archidata/UpdateJwtPublicKey.java @@ -0,0 +1,34 @@ +package org.kar.archidata; + +import org.kar.archidata.util.ConfigBaseVariable; +import org.kar.archidata.util.JWTWrapper; + +public class UpdateJwtPublicKey extends Thread { + boolean kill = false; + public void run() { + try { + Thread.sleep(1000*20, 0); + } catch (InterruptedException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + while (this.kill == false) { + // need to uppgrade when server call us... + try { + JWTWrapper.initLocalTokenRemote(ConfigBaseVariable.getSSOAddress(), "archidata"); + } catch (Exception e1) { + e1.printStackTrace(); + System.out.println("Can not retreive the basic tocken"); + return; + } + try { + Thread.sleep(1000*60*5, 0); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + public void kill() { + this.kill = true; + } +} \ No newline at end of file diff --git a/src/org/kar/archidata/UserDB.java b/src/org/kar/archidata/UserDB.java new file mode 100755 index 0000000..d638e1e --- /dev/null +++ b/src/org/kar/archidata/UserDB.java @@ -0,0 +1,133 @@ +package org.kar.archidata; + +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.model.User; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class UserDB { + + public UserDB() { + } + + public static User getUsers(long userId) throws Exception { + return SqlWrapper.get(User.class, userId); + /* + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "SELECT * FROM user WHERE id = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + User out = new User(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + return null; + */ + } + + + public static User getUserOrCreate(long userId, String userLogin) throws Exception { + User user = getUsers(userId); + if (user != null) { + /* + boolean blocked = false; + boolean removed = false; + if (user.email != userOAuth.email || user.login != userOAuth.login || user.blocked != blocked || user.removed != removed) { + updateUsersInfoFromOAuth(userOAuth.id, userOAuth.email, userOAuth.login, blocked, removed); + } else { + updateUsersConnectionTime(userOAuth.id); + } + return getUsers(userOAuth.id); + */ + return user; + } + createUsersInfoFromOAuth(userId, userLogin); + return getUsers(userId); + } +/* + private static void updateUsersConnectionTime(long userId) { + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "UPDATE `user` SET `lastConnection`=now(3) WHERE `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + + private static void updateUsersInfoFromOAuth(long userId, String email, String login, boolean blocked, boolean removed) { + DBEntry entry = new DBEntry(WebLauncher.dbConfig); + String query = "UPDATE `user` SET `login`=?, `email`=?, `lastConnection`=now(3), `blocked`=?, `removed`=? WHERE id = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setString(1, login); + ps.setString(2, email); + ps.setString(3, blocked ? "TRUE" : "FALSE"); + ps.setString(4, removed ? "TRUE" : "FALSE"); + ps.setLong(5, userId); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + */ + + private static void createUsersInfoFromOAuth(long userId, String login) { + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "INSERT INTO `user` (`id`, `login`, `lastConnection`, `admin`, `blocked`, `removed`) VALUE (?,?,now(3),'0','0','0')"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, userId); + ps.setString(2, login); + ps.executeUpdate(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/kar/archidata/annotation/PermitTokenInURI.java b/src/org/kar/archidata/annotation/PermitTokenInURI.java new file mode 100644 index 0000000..95a1117 --- /dev/null +++ b/src/org/kar/archidata/annotation/PermitTokenInURI.java @@ -0,0 +1,15 @@ +package org.kar.archidata.annotation; + +import javax.ws.rs.NameBinding; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@NameBinding +@Retention(RUNTIME) +@Target({METHOD}) +public @interface PermitTokenInURI { +} diff --git a/src/org/kar/archidata/annotation/SQLAutoIncrement.java b/src/org/kar/archidata/annotation/SQLAutoIncrement.java new file mode 100644 index 0000000..8c22c7d --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLAutoIncrement.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLAutoIncrement { + +} diff --git a/src/org/kar/archidata/annotation/SQLComment.java b/src/org/kar/archidata/annotation/SQLComment.java new file mode 100644 index 0000000..9bfa21f --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLComment.java @@ -0,0 +1,14 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLComment { + + String value(); + +} diff --git a/src/org/kar/archidata/annotation/SQLCreateTime.java b/src/org/kar/archidata/annotation/SQLCreateTime.java new file mode 100644 index 0000000..51dfdec --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLCreateTime.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLCreateTime { + +} diff --git a/src/org/kar/archidata/annotation/SQLDefault.java b/src/org/kar/archidata/annotation/SQLDefault.java new file mode 100644 index 0000000..ec88f2e --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLDefault.java @@ -0,0 +1,14 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLDefault { + + String value(); + +} diff --git a/src/org/kar/archidata/annotation/SQLIfNotExists.java b/src/org/kar/archidata/annotation/SQLIfNotExists.java new file mode 100644 index 0000000..9b185d6 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLIfNotExists.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLIfNotExists { + +} diff --git a/src/org/kar/archidata/annotation/SQLLimitSize.java b/src/org/kar/archidata/annotation/SQLLimitSize.java new file mode 100644 index 0000000..5ed10c4 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLLimitSize.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLLimitSize { + int value(); +} diff --git a/src/org/kar/archidata/annotation/SQLNotNull.java b/src/org/kar/archidata/annotation/SQLNotNull.java new file mode 100644 index 0000000..07a20aa --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLNotNull.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLNotNull { + +} diff --git a/src/org/kar/archidata/annotation/SQLNotRead.java b/src/org/kar/archidata/annotation/SQLNotRead.java new file mode 100644 index 0000000..50bb67b --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLNotRead.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLNotRead { + +} diff --git a/src/org/kar/archidata/annotation/SQLPrimaryKey.java b/src/org/kar/archidata/annotation/SQLPrimaryKey.java new file mode 100644 index 0000000..60944cf --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLPrimaryKey.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLPrimaryKey { + +} diff --git a/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java new file mode 100644 index 0000000..b8f9632 --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLTableLinkGeneric.java @@ -0,0 +1,20 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLTableLinkGeneric { + public enum ModelLink { + NONE, + INTERNAL, + EXTERNAL + }; + ModelLink value() default ModelLink.EXTERNAL; +} diff --git a/src/org/kar/archidata/annotation/SQLTableName.java b/src/org/kar/archidata/annotation/SQLTableName.java new file mode 100644 index 0000000..5902edc --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLTableName.java @@ -0,0 +1,14 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLTableName { + + String value(); + +} diff --git a/src/org/kar/archidata/annotation/SQLUpdateTime.java b/src/org/kar/archidata/annotation/SQLUpdateTime.java new file mode 100644 index 0000000..fe2ecad --- /dev/null +++ b/src/org/kar/archidata/annotation/SQLUpdateTime.java @@ -0,0 +1,12 @@ +package org.kar.archidata.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SQLUpdateTime { + +} diff --git a/src/org/kar/archidata/api/FrontGeneric.java b/src/org/kar/archidata/api/FrontGeneric.java new file mode 100644 index 0000000..7f699af --- /dev/null +++ b/src/org/kar/archidata/api/FrontGeneric.java @@ -0,0 +1,104 @@ +package org.kar.archidata.api; + +import java.io.File; +import java.util.List; + +import javax.annotation.security.PermitAll; +import javax.ws.rs.*; +import javax.ws.rs.core.CacheControl; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + + +public class FrontGeneric { + + protected String baseFrontFolder = "/data/front"; + + private String getExtension(String filename) { + if (filename.contains(".")) { + return filename.substring(filename.lastIndexOf(".") + 1); + } + return ""; + } + private Response retrive(String fileName) throws Exception { + String filePathName = baseFrontFolder + File.separator + fileName; + String extention = getExtension(filePathName); + String mineType = null; + System.out.println("try retrive : '" + filePathName + "' '" + extention + "'"); + if (extention.length() !=0 && extention.length() <= 5) { + if (extention.equalsIgnoreCase("jpg") || extention.equalsIgnoreCase("jpeg")) { + mineType = "image/jpeg"; + } else if (extention.equalsIgnoreCase("gif")) { + mineType = "image/gif"; + } else if (extention.equalsIgnoreCase("png")) { + mineType = "image/png"; + } else if (extention.equalsIgnoreCase("svg")) { + mineType = "image/svg+xml"; + } else if (extention.equalsIgnoreCase("webp")) { + mineType = "image/webp"; + } else if (extention.equalsIgnoreCase("js")) { + mineType = "application/javascript"; + } else if (extention.equalsIgnoreCase("json")) { + mineType = "application/json"; + } else if (extention.equalsIgnoreCase("ico")) { + mineType = "image/x-icon"; + } else if (extention.equalsIgnoreCase("html")) { + mineType = "text/html"; + } else if (extention.equalsIgnoreCase("css")) { + mineType = "text/css"; + } else { + return Response.status(403). + entity("Not supported model: '" + fileName + "'"). + type("text/plain"). + build(); + } + } else { + mineType = "text/html"; + filePathName = baseFrontFolder + File.separator + "index.html"; + } + System.out.println(" ==> '" + filePathName + "'"); + // reads input image + File download = new File(filePathName); + if (!download.exists()) { + return Response.status(404). + entity("Not Found: '" + fileName + "' extension='" + extention + "'"). + type("text/plain"). + build(); + } + ResponseBuilder response = Response.ok((Object)download); + // use this if I want to download the file: + //response.header("Content-Disposition", "attachment; filename=" + fileName); + CacheControl cc = new CacheControl(); + cc.setMaxAge(60); + cc.setNoCache(false); + response.cacheControl(cc); + response.type(mineType); + + return response.build(); + } + + @GET + @PermitAll() + //@Produces(MediaType.APPLICATION_OCTET_STREAM) + //@CacheMaxAge(time = 1, unit = TimeUnit.DAYS) + public Response retrive0() throws Exception { + return retrive("index.html"); + } + + @GET + @Path("{any: .*}") + @PermitAll() + //@Produces(MediaType.APPLICATION_OCTET_STREAM) + //@CacheMaxAge(time = 10, unit = TimeUnit.DAYS) + public Response retrive1(@PathParam("any") List segments) throws Exception { + String filename = ""; + for (PathSegment elem: segments) { + if (!filename.isEmpty()) { + filename += File.separator; + } + filename += elem.getPath(); + } + return retrive(filename); + } +} diff --git a/src/org/kar/archidata/db/DBConfig.java b/src/org/kar/archidata/db/DBConfig.java new file mode 100644 index 0000000..577a658 --- /dev/null +++ b/src/org/kar/archidata/db/DBConfig.java @@ -0,0 +1,60 @@ +package org.kar.archidata.db; + +public class DBConfig { + private final String hostname; + private final int port; + private final String login; + private final String password; + private final String dbName; + + public DBConfig(String hostname, Integer port, String login, String password, String dbName) { + if (hostname == null) { + this.hostname = "localhost"; + } else { + this.hostname = hostname; + } + if (port == null) { + this.port = 3306; + } else { + this.port = port; + } + this.login = login; + this.password = password; + this.dbName = dbName; + } + + @Override + public String toString() { + return "DBConfig{" + + "hostname='" + hostname + '\'' + + ", port=" + port + + ", login='" + login + '\'' + + ", password='" + password + '\'' + + ", dbName='" + dbName + '\'' + + '}'; + } + + public String getHostname() { + return hostname; + } + + public int getPort() { + return port; + } + + public String getLogin() { + return login; + } + + public String getPassword() { + return password; + } + + public String getDbName() { + return dbName; + } + + public String getUrl() { + return "jdbc:mysql://" + this.hostname + ":" + this.port + "/" + this.dbName + "?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC"; + } +} diff --git a/src/org/kar/archidata/db/DBEntry.java b/src/org/kar/archidata/db/DBEntry.java new file mode 100644 index 0000000..32c9f05 --- /dev/null +++ b/src/org/kar/archidata/db/DBEntry.java @@ -0,0 +1,45 @@ +package org.kar.archidata.db; + +import org.kar.archidata.model.User; + +import java.sql.*; + +public class DBEntry { + public DBConfig config; + public Connection connection; + + public DBEntry(DBConfig config) { + this.config = config; + connect(); + } + + public void connect() { + try { + connection = DriverManager.getConnection(config.getUrl(), config.getLogin(), config.getPassword()); + } catch (SQLException ex) { + ex.printStackTrace(); + } + + } + + public void disconnect() { + try { + //connection.commit(); + connection.close(); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } +/* + public void test() throws SQLException { + String query = "SELECT * FROM user"; + Statement st = connection.createStatement(); + ResultSet rs = st.executeQuery(query); + System.out.println("List of user:"); + if (rs.next()) { + User user = new User(rs); + System.out.println(" - " + user); + } + } + */ +} diff --git a/src/org/kar/archidata/filter/AuthenticationFilter.java b/src/org/kar/archidata/filter/AuthenticationFilter.java new file mode 100644 index 0000000..7a93842 --- /dev/null +++ b/src/org/kar/archidata/filter/AuthenticationFilter.java @@ -0,0 +1,198 @@ +package org.kar.archidata.filter; + +import java.lang.reflect.Method; +import javax.annotation.security.DenyAll; +import javax.annotation.security.PermitAll; +import javax.annotation.security.RolesAllowed; + + +import javax.annotation.Priority; +import javax.ws.rs.Priorities; +import javax.ws.rs.QueryParam; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.PathSegment; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; + +import org.kar.archidata.UserDB; +import org.kar.archidata.annotation.PermitTokenInURI; +import org.kar.archidata.model.User; +import org.kar.archidata.model.UserSmall; +import org.kar.archidata.util.JWTWrapper; + +import com.nimbusds.jwt.JWTClaimsSet; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +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 +// https://stackoverflow.com/questions/32817210/how-to-access-jersey-resource-secured-by-rolesallowed + +//@PreMatching +@Provider +@Priority(Priorities.AUTHENTICATION) +public class AuthenticationFilter implements ContainerRequestFilter { + @Context + private ResourceInfo resourceInfo; + + private static final String AUTHENTICATION_SCHEME = "Yota"; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + /* + System.out.println("-----------------------------------------------------"); + System.out.println("---- Check if have authorization ----"); + System.out.println("-----------------------------------------------------"); + System.out.println(" for:" + requestContext.getUriInfo().getPath()); + */ + Method method = resourceInfo.getResourceMethod(); + // Access denied for all + if(method.isAnnotationPresent(DenyAll.class)) { + System.out.println(" ==> deny all " + requestContext.getUriInfo().getPath()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access blocked !!!").build()); + return; + } + + //Access allowed for all + if( method.isAnnotationPresent(PermitAll.class)) { + System.out.println(" ==> permit all " + requestContext.getUriInfo().getPath()); + // no control ... + return; + } + // this is a security guard, all the API must define their access level: + if(!method.isAnnotationPresent(RolesAllowed.class)) { + System.out.println(" ==> missin @RolesAllowed " + requestContext.getUriInfo().getPath()); + requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build()); + return; + + } + + // Get the Authorization header from the request + String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); + //System.out.println("authorizationHeader: " + authorizationHeader); + if(authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) { + MultivaluedMap quaryparam = requestContext.getUriInfo().getQueryParameters(); + for (Entry> item: quaryparam.entrySet()) { + if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) { + if (!item.getValue().isEmpty()) { + authorizationHeader = item.getValue().get(0); + } + break; + } + } + } + //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("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) { + abortWithUnauthorized(requestContext); + } + if (user == null) { + abortWithUnauthorized(requestContext); + } + // create the security context model: + String scheme = requestContext.getUriInfo().getRequestUri().getScheme(); + MySecurityContext userContext = new MySecurityContext(user, scheme); + // retrieve the allowed right: + RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class); + List roles = Arrays.asList(rolesAnnotation.value()); + // check if the user have the right: + boolean haveRight = false; + for (String role : roles) { + if (userContext.isUserInRole(role)) { + haveRight = true; + break; + } + } + + //Is user valid? + if( ! haveRight) { + System.out.println("REJECTED not enought right : " + requestContext.getUriInfo().getPath() + " require: " + roles); + requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build()); + return; + } + requestContext.setSecurityContext(userContext); + System.out.println("Get local user : " + user); + } + + private boolean isTokenBasedAuthentication(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_SCHEME.toLowerCase() + " "); + } + + private void abortWithUnauthorized(ContainerRequestContext requestContext) { + + // Abort the filter chain with a 401 status code response + // The WWW-Authenticate header is sent along with the response + requestContext.abortWith( + Response.status(Response.Status.UNAUTHORIZED) + .header(HttpHeaders.WWW_AUTHENTICATE, + AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)") + .build()); + } + + private User validateToken(String authorization) throws Exception { + System.out.println(" validate token : " + authorization); + JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth"); + // check the token is valid !!! (signed and coherent issuer... + if (ret == null) { + System.out.println("The token is not valid: '" + authorization + "'"); + return null; + } + // 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") ); + } +} diff --git a/src/org/kar/archidata/filter/CORSFilter.java b/src/org/kar/archidata/filter/CORSFilter.java new file mode 100644 index 0000000..ce7f798 --- /dev/null +++ b/src/org/kar/archidata/filter/CORSFilter.java @@ -0,0 +1,25 @@ +package org.kar.archidata.filter; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + + +@Provider +public class CORSFilter implements ContainerResponseFilter { + + @Override + public void filter(ContainerRequestContext request, + ContainerResponseContext response) throws IOException { + //System.err.println("filter cors ..." + request.toString()); + + response.getHeaders().add("Access-Control-Allow-Origin", "*"); + response.getHeaders().add("Access-Control-Allow-Headers", "*"); + // "Origin, content-type, Content-type, Accept, authorization, mime-type, filename"); + response.getHeaders().add("Access-Control-Allow-Credentials", "true"); + response.getHeaders().add("Access-Control-Allow-Methods", + "GET, POST, PUT, DELETE, OPTIONS, HEAD"); + } +} diff --git a/src/org/kar/archidata/filter/GenericContext.java b/src/org/kar/archidata/filter/GenericContext.java new file mode 100644 index 0000000..faeb5c9 --- /dev/null +++ b/src/org/kar/archidata/filter/GenericContext.java @@ -0,0 +1,22 @@ +package org.kar.archidata.filter; + +import org.kar.archidata.model.User; + +import java.security.Principal; + +public class GenericContext implements Principal { + + public User user; + + public GenericContext(User user) { + this.user = user; + } + + @Override + public String getName() { + if (user == null) { + return "???"; + } + return user.login; + } +} diff --git a/src/org/kar/archidata/filter/MySecurityContext.java b/src/org/kar/archidata/filter/MySecurityContext.java new file mode 100644 index 0000000..b61a564 --- /dev/null +++ b/src/org/kar/archidata/filter/MySecurityContext.java @@ -0,0 +1,47 @@ +package org.kar.archidata.filter; + + +import org.kar.archidata.model.User; + +import javax.ws.rs.core.SecurityContext; +import java.security.Principal; + +// https://simplapi.wordpress.com/2015/09/19/jersey-jax-rs-securitycontext-in-action/ +class MySecurityContext implements SecurityContext { + + private final GenericContext contextPrincipale; + private final String sheme; + + public MySecurityContext(User user, String sheme) { + this.contextPrincipale = new GenericContext(user); + this.sheme = sheme; + } + + @Override + public Principal getUserPrincipal() { + return contextPrincipale; + } + + @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; + } + return false; + } + + @Override + public boolean isSecure() { + return true; + } + + @Override + public String getAuthenticationScheme() { + return "Yota"; + } + +} \ No newline at end of file diff --git a/src/org/kar/archidata/filter/OptionFilter.java b/src/org/kar/archidata/filter/OptionFilter.java new file mode 100644 index 0000000..bfe9527 --- /dev/null +++ b/src/org/kar/archidata/filter/OptionFilter.java @@ -0,0 +1,21 @@ +package org.kar.archidata.filter; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.Provider; +import java.io.IOException; + +@Provider +@PreMatching +public class OptionFilter implements ContainerRequestFilter { + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + if (requestContext.getMethod().contentEquals("OPTIONS")) { + requestContext.abortWith(Response.status(Response.Status.NO_CONTENT).build()); + } + } +} + + diff --git a/src/org/kar/archidata/internal/Log.java b/src/org/kar/archidata/internal/Log.java new file mode 100644 index 0000000..d8545ff --- /dev/null +++ b/src/org/kar/archidata/internal/Log.java @@ -0,0 +1,60 @@ +package org.kar.archidata.internal; + +//import io.scenarium.logger.LogLevel; +//import io.scenarium.logger.Logger; + +public class Log { +// private static final String LIB_NAME = "logger"; +// private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); +// private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); +// private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); +// private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); +// private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); +// private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); +// private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); +// private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); +// private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); +// +// private Log() {} +// +// public static void print(String data) { +// if (PRINT_PRINT) +// Logger.print(LIB_NAME_DRAW, data); +// } +// +// public static void todo(String data) { +// if (PRINT_TODO) +// Logger.todo(LIB_NAME_DRAW, data); +// } +// +// public static void critical(String data) { +// if (PRINT_CRITICAL) +// Logger.critical(LIB_NAME_DRAW, data); +// } +// +// public static void error(String data) { +// if (PRINT_ERROR) +// Logger.error(LIB_NAME_DRAW, data); +// } +// +// public static void warning(String data) { +// if (PRINT_WARNING) +// Logger.warning(LIB_NAME_DRAW, data); +// } +// +// public static void info(String data) { +// if (PRINT_INFO) +// Logger.info(LIB_NAME_DRAW, data); +// } +// +// public static void debug(String data) { +// if (PRINT_DEBUG) +// Logger.debug(LIB_NAME_DRAW, data); +// } +// +// public static void verbose(String data) { +// if (PRINT_VERBOSE) +// Logger.verbose(LIB_NAME_DRAW, data); +// } + +} diff --git a/src/org/kar/archidata/model/Data.java b/src/org/kar/archidata/model/Data.java new file mode 100644 index 0000000..a34617a --- /dev/null +++ b/src/org/kar/archidata/model/Data.java @@ -0,0 +1,32 @@ +package org.kar.archidata.model; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Data { + public Long id; + public boolean deleted; + public String sha512; + public String mimeType; + public Long size; + + public Data() { + + } + + public Data(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.deleted = rs.getBoolean(iii++); + this.sha512 = rs.getString(iii++); + this.mimeType = rs.getString(iii++); + this.size = rs.getLong(iii++); + if (rs.wasNull()) { + this.size = null; + } + } catch (SQLException ex) { + ex.printStackTrace(); + } + } +} diff --git a/src/org/kar/archidata/model/GenericTable.java b/src/org/kar/archidata/model/GenericTable.java new file mode 100644 index 0000000..8134c8e --- /dev/null +++ b/src/org/kar/archidata/model/GenericTable.java @@ -0,0 +1,35 @@ +package org.kar.archidata.model; + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +import org.kar.archidata.annotation.SQLComment; +import org.kar.archidata.annotation.SQLCreateTime; +import org.kar.archidata.annotation.SQLDefault; +import org.kar.archidata.annotation.SQLNotNull; +import org.kar.archidata.annotation.SQLNotRead; +import org.kar.archidata.annotation.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLUpdateTime; + +public class GenericTable { + @SQLAutoIncrement // Add AUTO_INCREMENT modifier + @SQLPrimaryKey // Create a PRIMARY KEY based on this field + @SQLNotNull + @SQLComment("Primary key of the base") + public Long id = null; + @SQLNotRead + @SQLNotNull + @SQLDefault("'0'") + @SQLComment("When delete, they are not removed, they are just set in a deleted state") + public Boolean deleted = null; + @SQLNotRead + @SQLCreateTime + @SQLNotNull + @SQLComment("Create time of the object") + public Timestamp create_date = null; + @SQLNotRead + @SQLUpdateTime + @SQLNotNull + @SQLComment("When update the object") + public Timestamp modify_date = null; +} diff --git a/src/org/kar/archidata/model/State.java b/src/org/kar/archidata/model/State.java new file mode 100644 index 0000000..bd3195e --- /dev/null +++ b/src/org/kar/archidata/model/State.java @@ -0,0 +1,12 @@ +package org.kar.archidata.model; + +public enum State { + // User has remove his account + REMOVED, + // User has been blocked his account + BLOCKED, + // generic user + USER, + // Administrator + ADMIN +} diff --git a/src/org/kar/archidata/model/Token.java b/src/org/kar/archidata/model/Token.java new file mode 100644 index 0000000..636cbfd --- /dev/null +++ b/src/org/kar/archidata/model/Token.java @@ -0,0 +1,57 @@ +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; + public String token; + public String createTime; + public String endValidityTime; + + public Token() { + } + + public Token(long id, long userId, String token, String createTime, String endValidityTime) { + this.id = id; + this.userId = userId; + this.token = token; + this.createTime = createTime; + this.endValidityTime = endValidityTime; + } + + public Token(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.userId = rs.getLong(iii++); + this.token = rs.getString(iii++); + this.createTime = rs.getString(iii++); + this.endValidityTime = rs.getString(iii++); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + + @Override + public String toString() { + return "Token{" + + "id=" + id + + ", userId=" + userId + + ", token='" + token + '\'' + + ", createTime=" + createTime + + ", endValidityTime=" + endValidityTime + + '}'; + } +} diff --git a/src/org/kar/archidata/model/User.java b/src/org/kar/archidata/model/User.java new file mode 100644 index 0000000..9fbf596 --- /dev/null +++ b/src/org/kar/archidata/model/User.java @@ -0,0 +1,53 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `avatar` bigint DEFAULT NULL, +) AUTO_INCREMENT=10; + + */ + +import java.sql.Timestamp; + +import org.kar.archidata.annotation.SQLAutoIncrement; +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.SQLPrimaryKey; +import org.kar.archidata.annotation.SQLTableName; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; + +@SQLTableName ("user") +@SQLIfNotExists +@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) +public class User { + @SQLAutoIncrement // Add AUTO_INCREMENT modifier + @SQLPrimaryKey // Create a PRIMARY KEY based on this field + @SQLNotNull + @SQLComment("Primary key of the base") + public Long id = null; + @SQLLimitSize(256) + public String login = null; + + public Timestamp lastConnection = null; + @SQLDefault("'0'") + @SQLNotNull + public boolean admin = false; + @SQLDefault("'0'") + @SQLNotNull + public boolean blocked = false; + @SQLDefault("'0'") + @SQLNotNull + public boolean removed = false; + +} diff --git a/src/org/kar/archidata/model/UserExtern.java b/src/org/kar/archidata/model/UserExtern.java new file mode 100644 index 0000000..2a1b61c --- /dev/null +++ b/src/org/kar/archidata/model/UserExtern.java @@ -0,0 +1,36 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE' +) AUTO_INCREMENT=10; + + */ + + +public class UserExtern { + public Long id; + public String login; + public boolean admin; + + public UserExtern(User other) { + this.id = other.id; + this.login = other.login; + this.admin = other.admin; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", admin=" + admin + + '}'; + } +} diff --git a/src/org/kar/archidata/model/UserPerso.java b/src/org/kar/archidata/model/UserPerso.java new file mode 100644 index 0000000..8c1be5b --- /dev/null +++ b/src/org/kar/archidata/model/UserPerso.java @@ -0,0 +1,42 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `lastConnection` datetime NOT NULL COMMENT 'last connection time', + `admin` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `blocked` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE', + `removed` enum("TRUE", "FALSE") NOT NULL DEFAULT 'FALSE' +) AUTO_INCREMENT=10; + + */ + + +public class UserPerso { + public Long id; + public String login; + public boolean admin; + public boolean blocked; + public boolean removed; + + public UserPerso(User other) { + this.id = other.id; + this.login = other.login; + this.admin = other.admin; + this.blocked = other.blocked; + this.removed = other.removed; + } + + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", admin=" + admin + + ", blocked=" + blocked + + ", removed=" + removed + + '}'; + } +} diff --git a/src/org/kar/archidata/model/UserSmall.java b/src/org/kar/archidata/model/UserSmall.java new file mode 100644 index 0000000..91cb8e8 --- /dev/null +++ b/src/org/kar/archidata/model/UserSmall.java @@ -0,0 +1,73 @@ +package org.kar.archidata.model; + +/* +CREATE TABLE `user` ( + `id` bigint NOT NULL COMMENT 'table ID' AUTO_INCREMENT PRIMARY KEY, + `login` varchar(128) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'login of the user', + `password` varchar(128) COLLATE 'latin1_bin' NOT NULL COMMENT 'password of the user hashed (sha512)', + `email` varchar(512) COLLATE 'utf8_general_ci' NOT NULL COMMENT 'email of the user', + `emailValidate` bigint COMMENT 'date of the email validation', + `newEmail` varchar(512) COLLATE 'utf8_general_ci' COMMENT 'email of the user if he want to change', + `authorisationLevel` enum("REMOVED", "USER", "ADMIN") NOT NULL COMMENT 'user level of authorization' +) AUTO_INCREMENT=10; + + */ + + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class UserSmall { + public long id; + public String login; + public String email; + public State authorisationLevel; + + public UserSmall() { + } + + public UserSmall(long id, String login, String email, State authorisationLevel) { + this.id = id; + this.login = login; + this.email = email; + this.authorisationLevel = authorisationLevel; + } + + public UserSmall(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.login = rs.getString(iii++); + this.email = rs.getString(iii++); + this.authorisationLevel = State.valueOf(rs.getString(iii++)); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + /* + public void serialize(ResultSet rs) { + int iii = 1; + try { + this.id = rs.getLong(iii++); + this.login = rs.getString(iii++); + this.password = rs.getString(iii++); + this.email = rs.getString(iii++); + this.emailValidate = rs.getLong(iii++); + this.newEmail = rs.getString(iii++); + this.authorisationLevel = State.valueOf(rs.getString(iii++)); + } catch (SQLException ex) { + ex.printStackTrace(); + } + } + */ + + @Override + public String toString() { + return "UserSmall{" + + "id='" + id + '\'' + + ", login='" + login + '\'' + + ", email='" + email + '\'' + + ", authorisationLevel=" + authorisationLevel + + '}'; + } +} diff --git a/src/org/kar/archidata/util/ConfigBaseVariable.java b/src/org/kar/archidata/util/ConfigBaseVariable.java new file mode 100644 index 0000000..c0ad146 --- /dev/null +++ b/src/org/kar/archidata/util/ConfigBaseVariable.java @@ -0,0 +1,78 @@ +package org.kar.archidata.util; + +public class ConfigBaseVariable { + + public static String getTmpDataFolder() { + String out = System.getenv("DATA_TMP_FOLDER"); + if (out == null) { + return "/application/data/tmp"; + } + return out; + } + + public static String getMediaDataFolder() { + String out = System.getenv("DATA_FOLDER"); + if (out == null) { + return "/application/data/media"; + } + return out; + } + + public static String getDBHost() { + String out = System.getenv("DB_HOST"); + if (out == null) { + return "localhost"; + } + return out; + } + + public static String getDBPort() { + String out = System.getenv("DB_PORT"); + if (out == null) { + return "80"; + //return "17036"; + } + return out; + } + + public static String getDBLogin() { + String out = System.getenv("DB_USER"); + if (out == null) { + return "root"; + } + return out; + } + + public static String getDBPassword() { + String out = System.getenv("DB_PASSWORD"); + if (out == null) { + return "archidata_password"; + } + return out; + } + + public static String getDBName() { + String out = System.getenv("DB_DATABASE"); + if (out == null) { + return "unknown"; + } + return out; + } + + public static String getlocalAddress() { + String out = System.getenv("API_ADDRESS"); + if (out == null) { + return "http://0.0.0.0:80/api/"; + } + return out; + } + + public static String getSSOAddress() { + String out = System.getenv("SSO_ADDRESS"); + if (out == null) { + return "http://sso_host/karauth/api/"; + //return "http://192.168.1.156/karauth/api/"; + } + return out; + } +} diff --git a/src/org/kar/archidata/util/DataTools.java b/src/org/kar/archidata/util/DataTools.java new file mode 100644 index 0000000..431fc9a --- /dev/null +++ b/src/org/kar/archidata/util/DataTools.java @@ -0,0 +1,346 @@ +package org.kar.archidata.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import javax.ws.rs.core.Response; + +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.SqlWrapper; +import org.kar.archidata.model.Data; +import org.kar.archidata.db.DBEntry; + +public class DataTools { + + public final static int CHUNK_SIZE = 1024 * 1024; // 1MB chunks + public final static int CHUNK_SIZE_IN = 50 * 1024 * 1024; // 1MB chunks + /** + * Upload some data + */ + private static long tmpFolderId = 1; + + public static void createFolder(String path) throws IOException { + if (!Files.exists(java.nio.file.Path.of(path))) { + System.out.println("Create folder: " + path); + Files.createDirectories(java.nio.file.Path.of(path)); + } + } + + public static long getTmpDataId() { + return tmpFolderId++; + } + public static String getTmpFileInData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static String getTmpFolder() { + String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++; + try { + createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static String getFileData(long tmpFolderId) { + String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data"; + try { + createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator); + } catch (IOException e) { + e.printStackTrace(); + } + return filePath; + } + + public static Data getWithSha512(String sha512) { + System.out.println("find sha512 = " + sha512); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "SELECT `id`, `deleted`, `sha512`, `mime_type`, `size` FROM `data` WHERE `sha512` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setString(1, sha512); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Data out = new Data(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + return null; + + } + + public static Data getWithId(long id) { + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "SELECT `id`, `deleted`, `sha512`, `mime_type`, `size` FROM `data` WHERE `deleted` = false AND `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, id); + ResultSet rs = ps.executeQuery(); + if (rs.next()) { + Data out = new Data(rs); + entry.disconnect(); + return out; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + return null; + } + + public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException, SQLException { + // determine mime type: + String mimeType = ""; + String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1); + switch (extension.toLowerCase()) { + case "jpg": + case "jpeg": + mimeType = "image/jpeg"; + break; + case "png": + mimeType = "image/png"; + break; + case "webp": + mimeType = "image/webp"; + break; + case "mka": + mimeType = "audio/x-matroska"; + break; + case "mkv": + mimeType = "video/x-matroska"; + break; + case "webm": + mimeType = "video/webm"; + break; + default: + throw new IOException("Can not find the mime type of data input: '" + extension + "'"); + } + String tmpPath = getTmpFileInData(tmpUID); + long fileSize = Files.size(Paths.get(tmpPath)); + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + long uniqueSQLID = -1; + try { + // prepare the request: + String query = "INSERT INTO `data` (`sha512`, `mime_type`, `size`, `original_name`) VALUES (?, ?, ?, ?)"; + PreparedStatement ps = entry.connection.prepareStatement(query, + Statement.RETURN_GENERATED_KEYS); + int iii = 1; + ps.setString(iii++, sha512); + ps.setString(iii++, mimeType); + ps.setLong(iii++, fileSize); + ps.setString(iii++, originalFileName); + // execute the request + int affectedRows = ps.executeUpdate(); + if (affectedRows == 0) { + throw new SQLException("Creating data failed, no rows affected."); + } + // retreive uid inserted + try (ResultSet generatedKeys = ps.getGeneratedKeys()) { + if (generatedKeys.next()) { + uniqueSQLID = generatedKeys.getLong(1); + } else { + throw new SQLException("Creating user failed, no ID obtained (1)."); + } + } catch (Exception ex) { + System.out.println("Can not get the UID key inserted ... "); + ex.printStackTrace(); + throw new SQLException("Creating user failed, no ID obtained (2)."); + } + } catch (SQLException ex) { + ex.printStackTrace(); + } + entry.disconnect(); + System.out.println("Add Data raw done. uid data=" + uniqueSQLID); + Data out = getWithId(uniqueSQLID); + + String mediaPath = getFileData(out.id); + System.out.println("src = " + tmpPath); + System.out.println("dst = " + mediaPath); + Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE); + + System.out.println("Move done"); + // all is done the file is corectly installed... + + return out; + } + + public static void undelete(Long id) { + DBEntry entry = new DBEntry(GlobalConfiguration.dbConfig); + String query = "UPDATE `data` SET `deleted` = false WHERE `id` = ?"; + try { + PreparedStatement ps = entry.connection.prepareStatement(query); + ps.setLong(1, id); + ps.execute(); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + entry.disconnect(); + } + + public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) { + return saveFile(uploadedInputStream, getTmpFileInData(idData)); + } + + public static void removeTemporaryFile(long idData) { + String filepath = getTmpFileInData(idData); + if (Files.exists(Paths.get(filepath))) { + try { + Files.delete(Paths.get(filepath)); + } catch (IOException e) { + System.out.println("can not delete temporary file : " + Paths.get(filepath)); + e.printStackTrace(); + } + } + } + + // save uploaded file to a defined location on the server + public static String saveFile(InputStream uploadedInputStream, String serverLocation) { + String out = ""; + try { + OutputStream outpuStream = new FileOutputStream(new File( + serverLocation)); + int read = 0; + byte[] bytes = new byte[CHUNK_SIZE_IN]; + MessageDigest md = MessageDigest.getInstance("SHA-512"); + + outpuStream = new FileOutputStream(new File(serverLocation)); + while ((read = uploadedInputStream.read(bytes)) != -1) { + //System.out.println("write " + read); + md.update(bytes, 0, read); + outpuStream.write(bytes, 0, read); + } + System.out.println("Flush input stream ... " + serverLocation); + System.out.flush(); + outpuStream.flush(); + outpuStream.close(); + // create the end of sha512 + byte[] sha512Digest = md.digest(); + // convert in hexadecimal + out = bytesToHex(sha512Digest); + uploadedInputStream.close(); + } catch (IOException ex) { + System.out.println("Can not write in temporary file ... "); + ex.printStackTrace(); + } catch (NoSuchAlgorithmException ex) { + System.out.println("Can not find sha512 algorithms"); + ex.printStackTrace(); + } + return out; + } + + // curl http://localhost:9993/api/users/3 + //@Secured + /* + @GET + @Path("{id}") + //@RolesAllowed("GUEST") + @Produces(MediaType.APPLICATION_OCTET_STREAM) + public Response retriveData(@HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception { + return retriveDataFull(range, id, "no-name"); + } + */ + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + public static String multipartCorrection(String data) { + if (data == null) { + return null; + } + if (data.isEmpty()) { + return null; + } + if (data.contentEquals("null")) { + return null; + } + return data; + } + + public static Response uploadCover(Class clazz, + Long id, + String fileName, + InputStream fileInputStream, + FormDataContentDisposition fileMetaData + ) { + try { + // correct input string stream : + fileName = multipartCorrection(fileName); + + //public NodeSmall uploadFile(final FormDataMultiPart form) { + System.out.println("Upload media file: " + fileMetaData); + System.out.println(" - id: " + id); + System.out.println(" - file_name: " + fileName); + System.out.println(" - fileInputStream: " + fileInputStream); + System.out.println(" - fileMetaData: " + fileMetaData); + System.out.flush(); + T media = SqlWrapper.get(clazz, id); + if (media == null) { + return Response.notModified("Media Id does not exist or removed...").build(); + } + + long tmpUID = getTmpDataId(); + String sha512 = saveTemporaryFile(fileInputStream, tmpUID); + Data data = getWithSha512(sha512); + if (data == null) { + System.out.println("Need to add the data in the BDD ... "); + System.out.flush(); + try { + data = createNewData(tmpUID, fileName, sha512); + } catch (IOException ex) { + removeTemporaryFile(tmpUID); + ex.printStackTrace(); + return Response.notModified("can not create input media").build(); + } catch (SQLException ex) { + ex.printStackTrace(); + removeTemporaryFile(tmpUID); + return Response.notModified("Error in SQL insertion ...").build(); + } + } else if (data.deleted == true) { + System.out.println("Data already exist but deleted"); + System.out.flush(); + undelete(data.id); + data.deleted = false; + } else { + System.out.println("Data already exist ... all good"); + System.out.flush(); + } + // Fist step: retrieve all the Id of each parents:... + System.out.println("Find typeNode"); + SqlWrapper.addLink(clazz, id, "cover", data.id); + return Response.ok(SqlWrapper.get(clazz, id)).build(); + } catch (Exception ex) { + System.out.println("Cat ann unexpected error ... "); + ex.printStackTrace(); + } + return Response.serverError().build(); + } +} diff --git a/src/org/kar/archidata/util/JWTWrapper.java b/src/org/kar/archidata/util/JWTWrapper.java new file mode 100644 index 0000000..85aeac0 --- /dev/null +++ b/src/org/kar/archidata/util/JWTWrapper.java @@ -0,0 +1,175 @@ +package org.kar.archidata.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.ParseException; +import java.util.Date; +import java.util.UUID; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JOSEObjectType; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +public class JWTWrapper { + private static RSAKey rsaJWK = null;; + private static RSAKey rsaPublicJWK = null; + + public static class PublicKey { + public String key; + + public PublicKey(String key) { + this.key = key; + } + public PublicKey() { + } + } + public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException { + // check Token: + URL obj = new URL(ssoUri + "public_key"); + System.out.println("Request token from:" + obj); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", application); + con.setRequestProperty("Cache-Control", "no-cache"); + con.setRequestProperty("Content-Type", "application/json"); + con.setRequestProperty("Accept", "application/json"); + int responseCode = con.getResponseCode(); + + System.out.println("GET Response Code :: " + responseCode); + if (responseCode == HttpURLConnection.HTTP_OK) { // success + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + + String inputLine; + StringBuffer response = new StringBuffer(); + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + // print result + //System.out.println(response.toString()); + ObjectMapper mapper = new ObjectMapper(); + PublicKey values = mapper.readValue(response.toString(), PublicKey.class); + rsaPublicJWK = RSAKey.parse(values.key); + return; + } + System.out.println("GET JWT validator token not worked"); + } + + public static void initLocalToken() 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(); + rsaJWK = new RSAKeyGenerator(2048).keyID(generatedStringForKey).generate(); + rsaPublicJWK = rsaJWK.toPublicJWK(); + //System.out.println("RSA key (all): " + rsaJWK.toJSONString()); + //System.out.println("RSA key (pub): " + rsaPublicJWK.toJSONString()); + } catch (JOSEException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + System.out.println("Can not generate teh public abnd private keys ..."); + rsaJWK = null; + rsaPublicJWK = null; + } + } + + public static void initValidateToken(String publicKey) { + try { + rsaPublicJWK = RSAKey.parse(publicKey); + } catch (ParseException e) { + e.printStackTrace(); + System.out.println("Can not retrieve public Key !!!!!!!! RSAKey='" + publicKey + "'"); + } + + } + public static String getPublicKey() { + if (rsaPublicJWK == null) { + return null; + } + return rsaPublicJWK.toJSONString(); + } + + /** + * Create a token with the provided elements + * @param userID UniqueId of the USER (global unique ID) + * @param userLogin Login of the user (never change) + * @param isuer The one who provide the Token + * @param timeOutInMunites Expiration of the token. + * @return the encoded token + */ + public static String generateJWToken(long userID, String userLogin, String isuer, int timeOutInMunites) { + if (rsaJWK == null) { + System.out.println("JWT private key is not present !!!"); + return null; + } + try { + // Create RSA-signer with the private key + JWSSigner signer = new RSASSASigner(rsaJWK); + // Prepare JWT with claims set + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + .subject(Long.toString(userID)) + .claim("login", userLogin) + .issuer(isuer) + .issueTime(new Date()) + .expirationTime(new Date(new Date().getTime() + 60 * timeOutInMunites * 1000 /* millisecond */)) + .build(); + + SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet); + + // Compute the RSA signature + signedJWT.sign(signer); + // serialize the output... + return signedJWT.serialize(); + } catch (JOSEException ex) { + ex.printStackTrace(); + } + return null; + } + + public static JWTClaimsSet validateToken(String signedToken, String isuer) { + if (rsaPublicJWK == null) { + System.out.println("JWT public key is not present !!!"); + return null; + } + try { + // On the consumer side, parse the JWS and verify its RSA signature + SignedJWT signedJWT = SignedJWT.parse(signedToken); + + JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK); + if (!signedJWT.verify(verifier)) { + System.out.println("JWT token is NOT verified "); + return null; + } + if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) { + System.out.println("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime() ); + return null; + } + if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) { + System.out.println("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'" ); + return null; + } + // the element must be validated outside ... + //System.out.println("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'"); + //System.out.println("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'"); + return signedJWT.getJWTClaimsSet(); + } catch (JOSEException ex) { + ex.printStackTrace(); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/org/kar/archidata/util/PublicKey.java b/src/org/kar/archidata/util/PublicKey.java new file mode 100644 index 0000000..f6968be --- /dev/null +++ b/src/org/kar/archidata/util/PublicKey.java @@ -0,0 +1,10 @@ +package org.kar.archidata.util; + + +public class PublicKey { + public String key; + + public PublicKey(String key) { + this.key = key; + } +} \ No newline at end of file