upgrade security and token management (add application and corect expiration date)
This commit is contained in:
parent
09ff403d9a
commit
044889129a
@ -15,3 +15,12 @@ generic interface for all KAR web application
|
||||
|
||||
|
||||
|
||||
Read instruction for tocken in ~/.m2/setting.xml
|
||||
|
||||
release:
|
||||
|
||||
mvn install
|
||||
mvn deploy
|
||||
|
||||
|
||||
|
||||
|
22
pom.xml
22
pom.xml
@ -1,9 +1,9 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>kar</groupId>
|
||||
<groupId>kangaroo-and-rabbit</groupId>
|
||||
<artifactId>archidata</artifactId>
|
||||
<version>0.1.0</version>
|
||||
<properties>
|
||||
<version>0.1.2</version>
|
||||
<properties>
|
||||
<jaxrs.version>2.1</jaxrs.version>
|
||||
<jersey.version>2.32</jersey.version>
|
||||
<jaxb.version>2.3.1</jaxb.version>
|
||||
@ -16,6 +16,22 @@
|
||||
<maven.dependency.version>3.1.1</maven.dependency.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>gitea</id>
|
||||
<url>https://gitea.atria-soft.org/api/packages/kangaroo-and-rabbit/maven</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
@ -34,6 +34,7 @@ import org.kar.archidata.annotation.SQLDefault;
|
||||
public class SqlWrapper {
|
||||
|
||||
public static class ExceptionDBInterface extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public int errorID;
|
||||
ExceptionDBInterface(int errorId, String message) {
|
||||
super(message);
|
||||
@ -692,6 +693,18 @@ public class SqlWrapper {
|
||||
ps.setShort(iii++, (Short)value);
|
||||
} else if (value.getClass() == Byte.class) {
|
||||
ps.setByte(iii++, (Byte)value);
|
||||
} else if (value.getClass() == Float.class) {
|
||||
ps.setFloat(iii++, (Float)value);
|
||||
} else if (value.getClass() == Double.class) {
|
||||
ps.setDouble(iii++, (Double)value);
|
||||
} else if (value.getClass() == Boolean.class) {
|
||||
ps.setBoolean(iii++, (Boolean)value);
|
||||
} else if (value.getClass() == Boolean.class) {
|
||||
ps.setBoolean(iii++, (Boolean)value);
|
||||
} else if (value.getClass() == Timestamp.class) {
|
||||
ps.setTimestamp(iii++, (Timestamp)value);
|
||||
} else if (value.getClass() == Date.class) {
|
||||
ps.setDate(iii++, (Date)value);
|
||||
} else {
|
||||
throw new Exception("Not manage type ==> need to add it ...");
|
||||
}
|
||||
|
14
src/org/kar/archidata/annotation/security/DenyAll.java
Normal file
14
src/org/kar/archidata/annotation/security/DenyAll.java
Normal file
@ -0,0 +1,14 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
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.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({METHOD})
|
||||
public @interface DenyAll {
|
||||
}
|
14
src/org/kar/archidata/annotation/security/PermitAll.java
Normal file
14
src/org/kar/archidata/annotation/security/PermitAll.java
Normal file
@ -0,0 +1,14 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
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.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({METHOD})
|
||||
public @interface PermitAll {
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.kar.archidata.annotation;
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
import javax.ws.rs.NameBinding;
|
||||
import java.lang.annotation.Retention;
|
15
src/org/kar/archidata/annotation/security/RolesAllowed.java
Normal file
15
src/org/kar/archidata/annotation/security/RolesAllowed.java
Normal file
@ -0,0 +1,15 @@
|
||||
package org.kar.archidata.annotation.security;
|
||||
|
||||
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.RetentionPolicy.RUNTIME;
|
||||
|
||||
@NameBinding
|
||||
@Retention(RUNTIME)
|
||||
@Target({METHOD})
|
||||
public @interface RolesAllowed {
|
||||
String[] value();
|
||||
}
|
@ -3,13 +3,14 @@ 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;
|
||||
|
||||
import org.kar.archidata.annotation.security.PermitAll;
|
||||
|
||||
|
||||
public class FrontGeneric {
|
||||
|
||||
|
@ -1,28 +1,25 @@
|
||||
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 org.kar.archidata.annotation.security.DenyAll;
|
||||
import org.kar.archidata.annotation.security.PermitAll;
|
||||
import org.kar.archidata.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.annotation.security.PermitTokenInURI;
|
||||
import org.kar.archidata.model.User;
|
||||
import org.kar.archidata.model.UserSmall;
|
||||
import org.kar.archidata.util.JWTWrapper;
|
||||
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
@ -68,10 +65,9 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
}
|
||||
// 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());
|
||||
System.out.println(" ==> missing @RolesAllowed " + requestContext.getUriInfo().getPath());
|
||||
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).entity("Access ILLEGAL !!!").build());
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Get the Authorization header from the request
|
||||
@ -133,10 +129,14 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
try {
|
||||
user = validateToken(token);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Fail to validate token: " + e.getMessage());
|
||||
abortWithUnauthorized(requestContext);
|
||||
return;
|
||||
}
|
||||
if (user == null) {
|
||||
System.out.println("get a NULL user ...");
|
||||
abortWithUnauthorized(requestContext);
|
||||
return;
|
||||
}
|
||||
// create the security context model:
|
||||
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
|
||||
@ -183,7 +183,7 @@ public class AuthenticationFilter implements ContainerRequestFilter {
|
||||
|
||||
private User validateToken(String authorization) throws Exception {
|
||||
System.out.println(" validate token : " + authorization);
|
||||
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth");
|
||||
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
|
||||
// check the token is valid !!! (signed and coherent issuer...
|
||||
if (ret == null) {
|
||||
System.out.println("The token is not valid: '" + authorization + "'");
|
||||
|
@ -36,7 +36,7 @@ public class User {
|
||||
@SQLNotNull
|
||||
@SQLComment("Primary key of the base")
|
||||
public Long id = null;
|
||||
@SQLLimitSize(256)
|
||||
@SQLLimitSize(128)
|
||||
public String login = null;
|
||||
|
||||
public Timestamp lastConnection = null;
|
||||
@ -49,5 +49,9 @@ public class User {
|
||||
@SQLDefault("'0'")
|
||||
@SQLNotNull
|
||||
public boolean removed = false;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User [login=" + login + ", last=" + lastConnection + ", admin=" + admin + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,78 +1,77 @@
|
||||
package org.kar.archidata.util;
|
||||
|
||||
public class ConfigBaseVariable {
|
||||
|
||||
static public String tmpDataFolder = System.getenv("DATA_TMP_FOLDER");
|
||||
static public String dataFolder = System.getenv("DATA_FOLDER");
|
||||
static public String dbHost = System.getenv("DB_HOST");
|
||||
static public String dbPort = System.getenv("DB_PORT");
|
||||
static public String dbUser = System.getenv("DB_USER");
|
||||
static public String dbPassword = System.getenv("DB_PASSWORD");
|
||||
static public String bdDatabase = System.getenv("DB_DATABASE");
|
||||
static public String apiAdress = System.getenv("API_ADDRESS");
|
||||
static public String ssoAdress = System.getenv("SSO_ADDRESS");
|
||||
|
||||
public static String getTmpDataFolder() {
|
||||
String out = System.getenv("DATA_TMP_FOLDER");
|
||||
if (out == null) {
|
||||
if (tmpDataFolder == null) {
|
||||
return "/application/data/tmp";
|
||||
}
|
||||
return out;
|
||||
return tmpDataFolder;
|
||||
}
|
||||
|
||||
public static String getMediaDataFolder() {
|
||||
String out = System.getenv("DATA_FOLDER");
|
||||
if (out == null) {
|
||||
if (dataFolder == null) {
|
||||
return "/application/data/media";
|
||||
}
|
||||
return out;
|
||||
return dataFolder;
|
||||
}
|
||||
|
||||
public static String getDBHost() {
|
||||
String out = System.getenv("DB_HOST");
|
||||
if (out == null) {
|
||||
if (dbHost == null) {
|
||||
return "localhost";
|
||||
}
|
||||
return out;
|
||||
return dbHost;
|
||||
}
|
||||
|
||||
public static String getDBPort() {
|
||||
String out = System.getenv("DB_PORT");
|
||||
if (out == null) {
|
||||
return "80";
|
||||
//return "17036";
|
||||
if (dbPort == null) {
|
||||
return "3306";
|
||||
}
|
||||
return out;
|
||||
return dbPort;
|
||||
}
|
||||
|
||||
public static String getDBLogin() {
|
||||
String out = System.getenv("DB_USER");
|
||||
if (out == null) {
|
||||
if (dbUser == null) {
|
||||
return "root";
|
||||
}
|
||||
return out;
|
||||
return dbUser;
|
||||
}
|
||||
|
||||
public static String getDBPassword() {
|
||||
String out = System.getenv("DB_PASSWORD");
|
||||
if (out == null) {
|
||||
return "archidata_password";
|
||||
if (dbPassword == null) {
|
||||
return "base_db_password";
|
||||
}
|
||||
return out;
|
||||
return dbPassword;
|
||||
}
|
||||
|
||||
public static String getDBName() {
|
||||
String out = System.getenv("DB_DATABASE");
|
||||
if (out == null) {
|
||||
if (bdDatabase == null) {
|
||||
return "unknown";
|
||||
}
|
||||
return out;
|
||||
return bdDatabase;
|
||||
}
|
||||
|
||||
public static String getlocalAddress() {
|
||||
String out = System.getenv("API_ADDRESS");
|
||||
if (out == null) {
|
||||
if (apiAdress == null) {
|
||||
return "http://0.0.0.0:80/api/";
|
||||
}
|
||||
return out;
|
||||
return apiAdress;
|
||||
}
|
||||
|
||||
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/";
|
||||
if (ssoAdress == null) {
|
||||
//return "http://sso_host/api/";
|
||||
return "http://192.168.1.156/karauth/api/";
|
||||
}
|
||||
return out;
|
||||
return ssoAdress;
|
||||
}
|
||||
}
|
||||
|
@ -110,11 +110,17 @@ public class JWTWrapper {
|
||||
* @param timeOutInMunites Expiration of the token.
|
||||
* @return the encoded token
|
||||
*/
|
||||
public static String generateJWToken(long userID, String userLogin, String isuer, int timeOutInMunites) {
|
||||
public static String generateJWToken(long userID, String userLogin, String isuer, String application, int timeOutInMunites) {
|
||||
if (rsaJWK == null) {
|
||||
System.out.println("JWT private key is not present !!!");
|
||||
return null;
|
||||
}
|
||||
/*
|
||||
System.out.println(" ===> expire in : " + timeOutInMunites);
|
||||
System.out.println(" ===>" + new Date().getTime());
|
||||
System.out.println(" ===>" + new Date(new Date().getTime()));
|
||||
System.out.println(" ===>" + new Date(new Date().getTime() - 60 * timeOutInMunites * 1000));
|
||||
*/
|
||||
try {
|
||||
// Create RSA-signer with the private key
|
||||
JWSSigner signer = new RSASSASigner(rsaJWK);
|
||||
@ -122,9 +128,10 @@ public class JWTWrapper {
|
||||
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
|
||||
.subject(Long.toString(userID))
|
||||
.claim("login", userLogin)
|
||||
.claim("application", application)
|
||||
.issuer(isuer)
|
||||
.issueTime(new Date())
|
||||
.expirationTime(new Date(new Date().getTime() + 60 * timeOutInMunites * 1000 /* millisecond */))
|
||||
.expirationTime(new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */)) // Do not ask why we need a "-" here ... this have no meaning
|
||||
.build();
|
||||
|
||||
SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
|
||||
@ -139,7 +146,7 @@ public class JWTWrapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JWTClaimsSet validateToken(String signedToken, String isuer) {
|
||||
public static JWTClaimsSet validateToken(String signedToken, String isuer, String application) {
|
||||
if (rsaPublicJWK == null) {
|
||||
System.out.println("JWT public key is not present !!!");
|
||||
return null;
|
||||
@ -161,6 +168,9 @@ public class JWTWrapper {
|
||||
System.out.println("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'" );
|
||||
return null;
|
||||
}
|
||||
if (application != null) {
|
||||
// TODO: verify the token is used for the correct application.
|
||||
}
|
||||
// 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() + "'");
|
||||
|
Loading…
Reference in New Issue
Block a user