[DEV] remove generic annotation and test json update

This commit is contained in:
Edouard DUPIN 2023-11-11 10:47:03 +01:00
parent f69bc8097a
commit c4fc49d91b
12 changed files with 498 additions and 350 deletions

View File

@ -1,14 +0,0 @@
package org.kar.archidata.annotation.security;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({ METHOD })
public @interface DenyAll {}

View File

@ -1,14 +0,0 @@
package org.kar.archidata.annotation.security;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({ METHOD })
public @interface PermitAll {}

View File

@ -1,16 +0,0 @@
package org.kar.archidata.annotation.security;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import jakarta.ws.rs.NameBinding;
@NameBinding
@Retention(RUNTIME)
@Target({ METHOD })
public @interface RolesAllowed {
String[] value();
}

View File

@ -22,15 +22,15 @@ import javax.imageio.ImageIO;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.dataAccess.DataAccess;
import org.kar.archidata.dataAccess.QueryCondition;
import org.kar.archidata.filter.GenericContext;
import org.kar.archidata.model.Data;
import org.kar.archidata.util.ConfigBaseVariable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
@ -61,133 +61,119 @@ public class DataResource {
* Upload some datas
*/
private static long tmpFolderId = 1;
private static void createFolder(String path) throws IOException {
private static void createFolder(final String path) throws IOException {
if (!Files.exists(java.nio.file.Path.of(path))) {
//Log.print("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;
public static String getTmpFileInData(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
} catch (final IOException e) {
e.printStackTrace();
}
return filePath;
}
public static String getFileData(long tmpFolderId) {
String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
public static String getFileData(final long tmpFolderId) {
final String filePath = ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator + "data";
try {
createFolder(ConfigBaseVariable.getMediaDataFolder() + File.separator + tmpFolderId + File.separator);
} catch (IOException e) {
} catch (final IOException e) {
e.printStackTrace();
}
return filePath;
}
public static Data getWithSha512(String sha512) {
public static Data getWithSha512(final String sha512) {
LOGGER.info("find sha512 = {}", sha512);
try {
return DataAccess.getWhere(Data.class, new QueryCondition("sha512", "=", sha512));
} catch (Exception e) {
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data getWithId(long id) {
public static Data getWithId(final long id) {
LOGGER.info("find id = {}", id);
try {
return DataAccess.get(Data.class, id);
} catch (Exception e) {
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static Data createNewData(long tmpUID, String originalFileName, String sha512) throws IOException {
public static Data createNewData(final long tmpUID, final String originalFileName, final String sha512) throws IOException {
// determine mime type:
Data injectedData = new Data();
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 + "'");
}
final String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1);
mimeType = switch (extension.toLowerCase()) {
case "jpg", "jpeg" -> "image/jpeg";
case "png" -> "image/png";
case "webp" -> "image/webp";
case "mka" -> "audio/x-matroska";
case "mkv" -> "video/x-matroska";
case "webm" -> "video/webm";
default -> throw new IOException("Can not find the mime type of data input: '" + extension + "'");
};
injectedData.mimeType = mimeType;
injectedData.sha512 = sha512;
String tmpPath = getTmpFileInData(tmpUID);
final String tmpPath = getTmpFileInData(tmpUID);
injectedData.size = Files.size(Paths.get(tmpPath));
try {
injectedData = DataAccess.insert(injectedData);
} catch (Exception e) {
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
String mediaPath = getFileData(injectedData.id);
final String mediaPath = getFileData(injectedData.id);
LOGGER.info("src = {}", tmpPath);
LOGGER.info("dst = {}", mediaPath);
Files.move(Paths.get(tmpPath), Paths.get(mediaPath), StandardCopyOption.ATOMIC_MOVE);
LOGGER.info("Move done");
return injectedData;
}
public static String saveTemporaryFile(InputStream uploadedInputStream, long idData) {
public static String saveTemporaryFile(final InputStream uploadedInputStream, final long idData) {
return saveFile(uploadedInputStream, DataResource.getTmpFileInData(idData));
}
public static void removeTemporaryFile(long idData) {
String filepath = DataResource.getTmpFileInData(idData);
public static void removeTemporaryFile(final long idData) {
final String filepath = DataResource.getTmpFileInData(idData);
if (Files.exists(Paths.get(filepath))) {
try {
Files.delete(Paths.get(filepath));
} catch (IOException e) {
} catch (final IOException e) {
LOGGER.info("can not delete temporary file : {}", Paths.get(filepath));
e.printStackTrace();
}
}
}
// save uploaded file to a defined location on the server
static String saveFile(InputStream uploadedInputStream, String serverLocation) {
static String saveFile(final InputStream uploadedInputStream, final 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");
final byte[] bytes = new byte[CHUNK_SIZE_IN];
final MessageDigest md = MessageDigest.getInstance("SHA-512");
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
//logger.info("write {}", read);
@ -199,95 +185,96 @@ public class DataResource {
outpuStream.flush();
outpuStream.close();
// create the end of sha512
byte[] sha512Digest = md.digest();
final byte[] sha512Digest = md.digest();
// convert in hexadecimal
out = bytesToHex(sha512Digest);
uploadedInputStream.close();
} catch (IOException ex) {
} catch (final IOException ex) {
LOGGER.info("Can not write in temporary file ... ");
ex.printStackTrace();
} catch (NoSuchAlgorithmException ex) {
} catch (final NoSuchAlgorithmException ex) {
LOGGER.info("Can not find sha512 algorithms");
ex.printStackTrace();
}
return out;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
public static String bytesToHex(final byte[] bytes) {
final StringBuilder sb = new StringBuilder();
for (final byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public Data getSmall(Long id) {
public Data getSmall(final Long id) {
try {
return DataAccess.get(Data.class, id);
} catch (Exception e) {
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@POST
@Path("/upload/")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@RolesAllowed("ADMIN")
public Response uploadFile(@Context SecurityContext sc, @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
public Response uploadFile(@Context final SecurityContext sc, @FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
LOGGER.info("===================================================");
LOGGER.info("== DATA uploadFile {}", (gc == null ? "null" : gc.userByToken));
LOGGER.info("===================================================");
//public NodeSmall uploadFile(final FormDataMultiPart form) {
LOGGER.info("Upload file: ");
String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
final String filePath = ConfigBaseVariable.getTmpDataFolder() + File.separator + tmpFolderId++;
try {
createFolder(ConfigBaseVariable.getTmpDataFolder() + File.separator);
} catch (IOException e) {
} catch (final IOException e) {
e.printStackTrace();
}
saveFile(fileInputStream, filePath);
return Response.ok("Data uploaded successfully !!").build();
//return null;
}
@GET
@Path("{id}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
public Response retriveDataId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
LOGGER.info("== DATA retriveDataId ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
final Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
@GET
@Path("thumbnail/{id}")
@RolesAllowed("USER")
@PermitTokenInURI
@Produces(MediaType.APPLICATION_OCTET_STREAM)
//@CacheMaxAge(time = 10, unit = TimeUnit.DAYS)
public Response retriveDataThumbnailId(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id)
throws Exception {
public Response retriveDataThumbnailId(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id) throws Exception {
//GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
//logger.info("== DATA retriveDataThumbnailId ? {}", (gc==null?"null":gc.user));
//logger.info("===================================================");
Data value = getSmall(id);
final Data value = getSmall(id);
if (value == null) {
return Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
File inputFile = new File(filePathName);
final String filePathName = ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data";
final File inputFile = new File(filePathName);
if (!inputFile.exists()) {
return Response.status(404).entity("{\"error\":\"media Does not exist: " + id + "\"}").type("application/json").build();
}
@ -295,31 +282,31 @@ public class DataResource {
// || value.mimeType.contentEquals("image/webp")
) {
// reads input image
BufferedImage inputImage = ImageIO.read(inputFile);
int scaledWidth = 250;
int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * (float) scaledWidth);
final BufferedImage inputImage = ImageIO.read(inputFile);
final int scaledWidth = 250;
final int scaledHeight = (int) ((float) inputImage.getHeight() / (float) inputImage.getWidth() * scaledWidth);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
final BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
final Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// create the output stream:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
// TODO: check how to remove buffer file !!! here, it is not needed at all...
ImageIO.write(outputImage, "JPG", baos);
} catch (IOException e) {
} catch (final IOException e) {
e.printStackTrace();
return Response.status(500).entity("Internal Error: resize fail: " + e.getMessage()).type("text/plain").build();
}
byte[] imageData = baos.toByteArray();
final byte[] imageData = baos.toByteArray();
//Response.ok(new ByteArrayInputStream(imageData)).build();
Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, imageData.length);
final Response.ResponseBuilder out = Response.ok(imageData).header(HttpHeaders.CONTENT_LENGTH, imageData.length);
out.type("image/jpeg");
// TODO: move this in a decorator !!!
CacheControl cc = new CacheControl();
final CacheControl cc = new CacheControl();
cc.setMaxAge(3600);
cc.setNoCache(false);
out.cacheControl(cc);
@ -327,26 +314,26 @@ public class DataResource {
}
return buildStream(filePathName, range, value.mimeType);
}
//@Secured
@GET
@Path("{id}/{name}")
@PermitTokenInURI
@RolesAllowed("USER")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response retriveDataFull(@Context SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) String token, @HeaderParam("Range") String range, @PathParam("id") Long id,
@PathParam("name") String name) throws Exception {
GenericContext gc = (GenericContext) sc.getUserPrincipal();
public Response retriveDataFull(@Context final SecurityContext sc, @QueryParam(HttpHeaders.AUTHORIZATION) final String token, @HeaderParam("Range") final String range,
@PathParam("id") final Long id, @PathParam("name") final String name) throws Exception {
final GenericContext gc = (GenericContext) sc.getUserPrincipal();
//logger.info("===================================================");
LOGGER.info("== DATA retriveDataFull ? id={} user={}", id, (gc == null ? "null" : gc.userByToken));
//logger.info("===================================================");
Data value = getSmall(id);
final Data value = getSmall(id);
if (value == null) {
Response.status(404).entity("media NOT FOUND: " + id).type("text/plain").build();
}
return buildStream(ConfigBaseVariable.getMediaDataFolder() + File.separator + id + File.separator + "data", range, value.mimeType);
}
/**
* Adapted from http://stackoverflow.com/questions/12768812/video-streaming-to-ipad-does-not-work-with-tapestry5/12829541#12829541
*
@ -354,70 +341,68 @@ public class DataResource {
* @return Streaming output
* @throws Exception IOException if an error occurs in streaming.
*/
private Response buildStream(final String filename, final String range, String mimeType) throws Exception {
File file = new File(filename);
private Response buildStream(final String filename, final String range, final String mimeType) throws Exception {
final File file = new File(filename);
//logger.info("request range : {}", range);
// range not requested : Firefox does not send range headers
if (range == null) {
final StreamingOutput output = new StreamingOutput() {
@Override
public void write(OutputStream out) {
public void write(final OutputStream out) {
try (FileInputStream in = new FileInputStream(file)) {
byte[] buf = new byte[1024 * 1024];
final byte[] buf = new byte[1024 * 1024];
int len;
while ((len = in.read(buf)) != -1) {
try {
out.write(buf, 0, len);
out.flush();
//logger.info("---- wrote {} bytes file ----", len);
} catch (IOException ex) {
} catch (final IOException ex) {
LOGGER.info("remote close connection");
break;
}
}
} catch (IOException ex) {
} catch (final IOException ex) {
throw new InternalServerErrorException(ex);
}
}
};
Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length());
final Response.ResponseBuilder out = Response.ok(output).header(HttpHeaders.CONTENT_LENGTH, file.length());
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
String[] ranges = range.split("=")[1].split("-");
final String[] ranges = range.split("=")[1].split("-");
final long from = Long.parseLong(ranges[0]);
//logger.info("request range : {}", ranges.length);
//Chunk media if the range upper bound is unspecified. Chrome, Opera sends "bytes=0-"
long to = CHUNK_SIZE + from;
if (ranges.length == 1) {
to = file.length() - 1;
} else {
if (to >= file.length()) {
to = (long) (file.length() - 1);
}
} else if (to >= file.length()) {
to = file.length() - 1;
}
final String responseRange = String.format("bytes %d-%d/%d", from, to, file.length());
//logger.info("responseRange: {}", responseRange);
final RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(from);
final long len = to - from + 1;
final MediaStreamer streamer = new MediaStreamer(len, raf);
Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT).header("Accept-Ranges", "bytes").header("Content-Range", responseRange)
final Response.ResponseBuilder out = Response.ok(streamer).status(Response.Status.PARTIAL_CONTENT).header("Accept-Ranges", "bytes").header("Content-Range", responseRange)
.header(HttpHeaders.CONTENT_LENGTH, streamer.getLenth()).header(HttpHeaders.LAST_MODIFIED, new Date(file.lastModified()));
if (mimeType != null) {
out.type(mimeType);
}
return out.build();
}
public static void undelete(Long id) throws Exception {
public static void undelete(final Long id) throws Exception {
DataAccess.unsetDelete(Data.class, id);
}
}

View File

@ -3,10 +3,10 @@ package org.kar.archidata.api;
import java.io.File;
import java.util.List;
import org.kar.archidata.annotation.security.PermitAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.NotSupportedException;
@ -19,19 +19,19 @@ import jakarta.ws.rs.core.Response.ResponseBuilder;
public class FrontGeneric {
private static final Logger LOGGER = LoggerFactory.getLogger(FrontGeneric.class);
protected String baseFrontFolder = "/data/front";
private String getExtension(String filename) {
private String getExtension(final 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);
private Response retrive(final String fileName) throws Exception {
String filePathName = this.baseFrontFolder + File.separator + fileName;
final String extention = getExtension(filePathName);
String mineType = null;
LOGGER.debug("try retrive : '{}' '{}'", filePathName, extention);
if (extention.length() != 0 && extention.length() <= 5) {
@ -66,26 +66,26 @@ public class FrontGeneric {
}
} else {
mineType = "text/html";
filePathName = baseFrontFolder + File.separator + "index.html";
filePathName = this.baseFrontFolder + File.separator + "index.html";
}
LOGGER.debug(" ==> '[}'", filePathName);
// reads input image
File download = new File(filePathName);
final File download = new File(filePathName);
if (!download.exists()) {
throw new NotFoundException("Not Found: '" + fileName + "' extension='" + extention + "'");
}
ResponseBuilder response = Response.ok((Object) download);
final ResponseBuilder response = Response.ok(download);
// use this if I want to download the file:
//response.header("Content-Disposition", "attachment; filename=" + fileName);
CacheControl cc = new CacheControl();
final 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)
@ -93,15 +93,15 @@ public class FrontGeneric {
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<PathSegment> segments) throws Exception {
public Response retrive1(@PathParam("any") final List<PathSegment> segments) throws Exception {
String filename = "";
for (PathSegment elem : segments) {
for (final PathSegment elem : segments) {
if (!filename.isEmpty()) {
filename += File.separator;
}

View File

@ -14,11 +14,11 @@ import jakarta.ws.rs.core.StreamingOutput;
public class MediaStreamer implements StreamingOutput {
private static final Logger LOGGER = LoggerFactory.getLogger(MediaStreamer.class);
private final int CHUNK_SIZE = 1024 * 1024; // 1MB chunks
final byte[] buf = new byte[CHUNK_SIZE];
final byte[] buf = new byte[this.CHUNK_SIZE];
private long length;
private RandomAccessFile raf;
public MediaStreamer(long length, RandomAccessFile raf) throws IOException {
private final RandomAccessFile raf;
public MediaStreamer(final long length, final RandomAccessFile raf) throws IOException {
//logger.info("request stream of {} data", length / 1024);
if (length < 0) {
throw new IOException("Wrong size of the file to stream: " + length);
@ -28,34 +28,34 @@ public class MediaStreamer implements StreamingOutput {
}
@Override
public void write(OutputStream outputStream) {
public void write(final OutputStream outputStream) {
try {
while (length != 0) {
int read = raf.read(buf, 0, buf.length > length ? (int) length : buf.length);
while (this.length != 0) {
final int read = this.raf.read(this.buf, 0, this.buf.length > this.length ? (int) this.length : this.buf.length);
try {
outputStream.write(buf, 0, read);
} catch (IOException ex) {
outputStream.write(this.buf, 0, read);
} catch (final IOException ex) {
LOGGER.info("remote close connection");
break;
}
length -= read;
this.length -= read;
}
} catch (IOException ex) {
} catch (final IOException ex) {
throw new InternalServerErrorException(ex);
} catch (WebApplicationException ex) {
} catch (final WebApplicationException ex) {
throw new InternalServerErrorException(ex);
} finally {
try {
raf.close();
} catch (IOException ex) {
this.raf.close();
} catch (final IOException ex) {
ex.printStackTrace();
throw new InternalServerErrorException(ex);
}
}
}
public long getLenth() {
return length;
return this.length;
}
}

View File

@ -623,7 +623,7 @@ public class DataAccess {
// check the compatibility of the id and the declared ID
final Class<?> typeClass = idField.getType();
if (id == typeClass) {
throw new Exception("Request update with the wriong type ...");
throw new Exception("Request update with the wrong type ...");
}
// Udpade Json Value
return updateWithJson(clazz, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), jsonData);
@ -638,15 +638,15 @@ public class DataAccess {
final List<String> keys = new ArrayList<>();
final var iterator = root.fieldNames();
iterator.forEachRemaining(e -> keys.add(e));
return update(data, condition, keys);
return updateWhere(data, condition, null, keys);
}
public static <T, ID_TYPE> int update(final T data, final ID_TYPE id) throws Exception {
return update(data, id, null);
}
public static <T> int update(final T data, final QueryItem condition) throws Exception {
return update(data, condition, null);
public static <T> int updateWhere(final T data, final QueryItem condition) throws Exception {
return updateWhere(data, condition, null, null);
}
/**

View File

@ -10,10 +10,7 @@ import java.util.Map.Entry;
// 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
import org.kar.archidata.annotation.security.DenyAll;
import org.kar.archidata.annotation.security.PermitAll;
import org.kar.archidata.annotation.security.PermitTokenInURI;
import org.kar.archidata.annotation.security.RolesAllowed;
import org.kar.archidata.catcher.RestErrorResponse;
import org.kar.archidata.model.UserByToken;
import org.kar.archidata.util.JWTWrapper;
@ -23,6 +20,9 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.jwt.JWTClaimsSet;
import jakarta.annotation.Priority;
import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
@ -42,31 +42,30 @@ public class AuthenticationFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
protected final String applicationName;
private static final String AUTHENTICATION_SCHEME = "Yota";
private static final String AUTHENTICATION_TOKEN_SCHEME = "Zota";
public AuthenticationFilter(String applicationName) {
super();
public AuthenticationFilter(final String applicationName) {
this.applicationName = applicationName;
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
public void filter(final ContainerRequestContext requestContext) throws IOException {
/*
logger.debug("-----------------------------------------------------");
logger.debug("---- Check if have authorization ----");
logger.debug("-----------------------------------------------------");
logger.debug(" for:{}", requestContext.getUriInfo().getPath());
*/
Method method = resourceInfo.getResourceMethod();
final Method method = this.resourceInfo.getResourceMethod();
// Access denied for all
if (method.isAnnotationPresent(DenyAll.class)) {
logger.debug(" ==> deny all {}", requestContext.getUriInfo().getPath());
this.logger.debug(" ==> 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)) {
//logger.debug(" ==> permit all " + requestContext.getUriInfo().getPath());
@ -75,17 +74,17 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
// this is a security guard, all the API must define their access level:
if (!method.isAnnotationPresent(RolesAllowed.class)) {
logger.error(" ==> missing @RolesAllowed {}", requestContext.getUriInfo().getPath());
this.logger.error(" ==> missing @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);
//logger.debug("authorizationHeader: {}", authorizationHeader);
if (authorizationHeader == null && method.isAnnotationPresent(PermitTokenInURI.class)) {
MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
for (Entry<String, List<String>> item : quaryparam.entrySet()) {
final MultivaluedMap<String, String> quaryparam = requestContext.getUriInfo().getQueryParameters();
for (final Entry<String, List<String>> item : quaryparam.entrySet()) {
if (item.getKey().equals(HttpHeaders.AUTHORIZATION)) {
if (!item.getValue().isEmpty()) {
authorizationHeader = item.getValue().get(0);
@ -95,58 +94,58 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
}
// logger.debug("authorizationHeader: {}", authorizationHeader);
boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
final boolean isApplicationToken = isApplicationTokenBasedAuthentication(authorizationHeader);
final boolean isJwtToken = isTokenBasedAuthentication(authorizationHeader);
// Validate the Authorization header data Model "Yota jwt.to.ken" "Zota tokenId:hash(token)"
if (!isApplicationToken && !isJwtToken) {
logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
this.logger.warn("REJECTED unauthorized: {}", requestContext.getUriInfo().getPath());
abortWithUnauthorized(requestContext, "REJECTED unauthorized: " + requestContext.getUriInfo().getPath());
return;
}
UserByToken userByToken = null;
if (isJwtToken) {
// Extract the token from the Authorization header (Remove "Yota ")
String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
final String token = authorizationHeader.substring(AUTHENTICATION_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateJwtToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
} catch (final Exception e) {
this.logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL user ...");
this.logger.warn("get a NULL user ...");
abortWithUnauthorized(requestContext, "get a NULL user ...");
return;
}
} else {
// Extract the token from the Authorization header (Remove "Zota ")
String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
final String token = authorizationHeader.substring(AUTHENTICATION_TOKEN_SCHEME.length()).trim();
//logger.debug("token: {}", token);
try {
userByToken = validateToken(token);
} catch (Exception e) {
logger.error("Fail to validate token: {}", e.getMessage());
} catch (final Exception e) {
this.logger.error("Fail to validate token: {}", e.getMessage());
abortWithUnauthorized(requestContext, "Fail to validate token: " + e.getMessage());
return;
}
if (userByToken == null) {
logger.warn("get a NULL application ...");
this.logger.warn("get a NULL application ...");
abortWithUnauthorized(requestContext, "get a NULL application ...");
return;
}
}
// create the security context model:
String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
final String scheme = requestContext.getUriInfo().getRequestUri().getScheme();
final MySecurityContext userContext = new MySecurityContext(userByToken, scheme);
// retrieve the allowed right:
RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
List<String> roles = Arrays.asList(rolesAnnotation.value());
final RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
final List<String> roles = Arrays.asList(rolesAnnotation.value());
// check if the user have the right:
boolean haveRight = false;
for (String role : roles) {
for (final String role : roles) {
if (userContext.isUserInRole(role)) {
haveRight = true;
break;
@ -154,67 +153,67 @@ public class AuthenticationFilter implements ContainerRequestFilter {
}
//Is user valid?
if (!haveRight) {
logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
this.logger.error("REJECTED not enought right : {} require: {}", requestContext.getUriInfo().getPath(), roles);
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("Not enought RIGHT !!!").build());
return;
}
requestContext.setSecurityContext(userContext);
// logger.debug("Get local user : {} / {}", user, userByToken);
}
private boolean isTokenBasedAuthentication(String authorizationHeader) {
private boolean isTokenBasedAuthentication(final 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 boolean isApplicationTokenBasedAuthentication(String authorizationHeader) {
private boolean isApplicationTokenBasedAuthentication(final String authorizationHeader) {
// Check if the Authorization header is valid
// It must not be null and must be prefixed with "Bearer" plus a whitespace
// The authentication scheme comparison must be case-insensitive
return authorizationHeader != null && authorizationHeader.toLowerCase().startsWith(AUTHENTICATION_TOKEN_SCHEME.toLowerCase() + " ");
}
private void abortWithUnauthorized(ContainerRequestContext requestContext, String message) {
private void abortWithUnauthorized(final ContainerRequestContext requestContext, final String message) {
// Abort the filter chain with a 401 status code response
// The WWW-Authenticate header is sent along with the response
logger.warn("abortWithUnauthorized:");
RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
logger.error("Error UUID={}", ret.uuid);
this.logger.warn("abortWithUnauthorized:");
final RestErrorResponse ret = new RestErrorResponse(Response.Status.UNAUTHORIZED, "Unauthorized", message);
this.logger.error("Error UUID={}", ret.uuid);
requestContext.abortWith(Response.status(ret.status).header(HttpHeaders.WWW_AUTHENTICATE, AUTHENTICATION_SCHEME + " base64(HEADER).base64(CONTENT).base64(KEY)").entity(ret)
.type(MediaType.APPLICATION_JSON).build());
}
protected UserByToken validateToken(String authorization) throws Exception {
logger.info("Must be Override by the application implmentation, otherwise it dose not work");
protected UserByToken validateToken(final String authorization) throws Exception {
this.logger.info("Must be Override by the application implmentation, otherwise it dose not work");
return null;
}
// must be override to be good implementation
protected UserByToken validateJwtToken(String authorization) throws Exception {
protected UserByToken validateJwtToken(final String authorization) throws Exception {
//logger.debug(" validate token : " + authorization);
JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
final JWTClaimsSet ret = JWTWrapper.validateToken(authorization, "KarAuth", null);
// check the token is valid !!! (signed and coherent issuer...
if (ret == null) {
logger.error("The token is not valid: '{}'", authorization);
this.logger.error("The token is not valid: '{}'", authorization);
return null;
}
// check userID
String userUID = ret.getSubject();
long id = Long.parseLong(userUID);
UserByToken user = new UserByToken();
final String userUID = ret.getSubject();
final long id = Long.parseLong(userUID);
final UserByToken user = new UserByToken();
user.id = id;
user.name = (String) ret.getClaim("login");
user.type = UserByToken.TYPE_USER;
Object rowRight = ret.getClaim("right");
final Object rowRight = ret.getClaim("right");
if (rowRight != null) {
Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
final Map<String, Map<String, Object>> rights = (Map<String, Map<String, Object>>) ret.getClaim("right");
if (rights.containsKey(this.applicationName)) {
user.right = rights.get(this.applicationName);
} else {
logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
this.logger.error("Connect with no right for this application='{}' full Right='{}'", this.applicationName, rights);
}
}
//logger.debug("request user: '{}' right: '{}' row='{}'", userUID, user.right, rowRight);

View File

@ -4,6 +4,4 @@ import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record GetToken(
String jwt) {
}
String jwt) {}

View File

@ -13,7 +13,8 @@ public class ConfigBaseVariable {
static public String apiAdress;
static public String ssoAdress;
static public String ssoToken;
static public String testMode;
// For test only
public static void clearAllValue() {
tmpDataFolder = System.getenv("DATA_TMP_FOLDER");
@ -28,82 +29,83 @@ public class ConfigBaseVariable {
apiAdress = System.getenv("API_ADDRESS");
ssoAdress = System.getenv("SSO_ADDRESS");
ssoToken = System.getenv("SSO_TOKEN");
testMode = System.getenv("TEST_MODE");
}
static {
clearAllValue();
}
public static String getTmpDataFolder() {
if (tmpDataFolder == null) {
return "/application/data/tmp";
}
return tmpDataFolder;
}
public static String getMediaDataFolder() {
if (dataFolder == null) {
return "/application/data/media";
}
return dataFolder;
}
public static String getDBType() {
if (dbType == null) {
return "mysql";
}
return dbType;
}
public static String getDBHost() {
if (dbHost == null) {
return "localhost";
}
return dbHost;
}
public static String getDBPort() {
if (dbPort == null) {
return "3306";
}
return dbPort;
}
public static String getDBLogin() {
if (dbUser == null) {
return "root";
}
return dbUser;
}
public static String getDBPassword() {
if (dbPassword == null) {
return "base_db_password";
}
return dbPassword;
}
public static String getDBName() {
if (bdDatabase == null) {
return "unknown";
}
return bdDatabase;
}
public static boolean getDBKeepConnected() {
if (dbKeepConnected == null) {
return false;
}
return Boolean.parseBoolean(dbKeepConnected);
}
public static String getlocalAddress() {
if (apiAdress == null) {
return "http://0.0.0.0:80/api/";
}
return apiAdress;
}
public static String getSSOAddress() {
return ssoAdress;
}
@ -111,4 +113,11 @@ public class ConfigBaseVariable {
public static String ssoToken() {
return ssoToken;
}
public static boolean getTestMode() {
if (testMode == null) {
return false;
}
return Boolean.parseBoolean(testMode);
}
}

View File

@ -8,6 +8,7 @@ import java.net.URL;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.slf4j.Logger;
@ -18,108 +19,148 @@ import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
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.jca.JCAContext;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
public class JWTWrapper {
static final Logger logger = LoggerFactory.getLogger(JWTWrapper.class);
class TestSigner implements JWSSigner {
public static String test_signature = "TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E";
/**
* Signs the specified {@link JWSObject#getSigningInput input} of a
* {@link JWSObject JWS object}.
*
* @param header The JSON Web Signature (JWS) header. Must
* specify a supported JWS algorithm and must not
* be {@code null}.
* @param signingInput The input to sign. Must not be {@code null}.
*
* @return The resulting signature part (third part) of the JWS object.
*
* @throws JOSEException If the JWS algorithm is not supported, if a
* critical header parameter is not supported or
* marked for deferral to the application, or if
* signing failed for some other internal reason.
*/
@Override
public Base64URL sign(final JWSHeader header, final byte[] signingInput) throws JOSEException {
return new Base64URL(test_signature);
}
@Override
public Set<JWSAlgorithm> supportedJWSAlgorithms() {
// TODO Auto-generated method stub
return null;
}
@Override
public JCAContext getJCAContext() {
// TODO Auto-generated method stub
return null;
}
}
public class JWTWrapper {
static final Logger LOGGER = LoggerFactory.getLogger(JWTWrapper.class);
private static RSAKey rsaJWK = null;;
private static RSAKey rsaPublicJWK = null;
public static class PublicKey {
public String key;
public PublicKey(String key) {
public PublicKey(final String key) {
this.key = key;
}
public PublicKey() {}
}
public static void initLocalTokenRemote(String ssoUri, String application) throws IOException, ParseException {
public static void initLocalTokenRemote(final String ssoUri, final String application) throws IOException, ParseException {
// check Token:
URL obj = new URL(ssoUri + "public_key");
//logger.debug("Request token from: {}", obj);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
final URL obj = new URL(ssoUri + "public_key");
//LOGGER.debug("Request token from: {}", obj);
final 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");
String ssoToken = ConfigBaseVariable.ssoToken();
final String ssoToken = ConfigBaseVariable.ssoToken();
if (ssoToken != null) {
con.setRequestProperty("Authorization", "Zota " + ssoToken);
}
int responseCode = con.getResponseCode();
//logger.debug("GET Response Code :: {}", responseCode);
final int responseCode = con.getResponseCode();
//LOGGER.debug("GET Response Code :: {}", responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
final BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
final StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
//logger.debug(response.toString());
ObjectMapper mapper = new ObjectMapper();
PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
//LOGGER.debug(response.toString());
final ObjectMapper mapper = new ObjectMapper();
final PublicKey values = mapper.readValue(response.toString(), PublicKey.class);
rsaPublicJWK = RSAKey.parse(values.key);
return;
}
logger.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
LOGGER.debug("GET JWT validator token not worked response code {} from {} ", responseCode, obj);
}
public static void initLocalToken(String baseUUID) throws Exception {
// RSA signatures require a public and private RSA key pair, the public key
public static void initLocalToken(final String baseUUID) throws Exception {
// RSA signatures require a public and private RSA key pair, the public key
// must be made known to the JWS recipient in order to verify the signatures
try {
String generatedStringForKey = baseUUID;
if (generatedStringForKey == null) {
logger.error(" Generate new UUID : {}", generatedStringForKey);
LOGGER.error(" Generate new UUID : {}", generatedStringForKey);
generatedStringForKey = UUID.randomUUID().toString();
} else {
logger.error("USE UUID : {}", generatedStringForKey);
LOGGER.error("USE UUID : {}", generatedStringForKey);
}
rsaJWK = new RSAKeyGenerator(2048).keyID(generatedStringForKey).generate();
rsaPublicJWK = rsaJWK.toPublicJWK();
logger.error("RSA key (all): " + rsaJWK.toJSONString());
logger.error("RSA key (pub): " + rsaPublicJWK.toJSONString());
} catch (JOSEException e) {
LOGGER.error("RSA key (all): " + rsaJWK.toJSONString());
LOGGER.error("RSA key (pub): " + rsaPublicJWK.toJSONString());
} catch (final JOSEException e) {
// TODO Auto-generated catch block
e.printStackTrace();
logger.debug("Can not generate teh public abnd private keys ...");
LOGGER.debug("Can not generate teh public abnd private keys ...");
rsaJWK = null;
rsaPublicJWK = null;
}
}
public static void initValidateToken(String publicKey) {
public static void initValidateToken(final String publicKey) {
try {
rsaPublicJWK = RSAKey.parse(publicKey);
} catch (ParseException e) {
} catch (final ParseException e) {
e.printStackTrace();
logger.debug("Can not retrieve public Key !!!!!!!! RSAKey='{}'", publicKey);
LOGGER.debug("Can not retrieve public Key !!!!!!!! RSAKey='{}'", publicKey);
}
}
public static String getPublicKeyJson() {
if (rsaPublicJWK == null) {
return null;
}
return rsaPublicJWK.toJSONString();
}
public static java.security.interfaces.RSAPublicKey getPublicKeyJava() throws JOSEException {
if (rsaPublicJWK == null) {
return null;
@ -127,7 +168,7 @@ public class JWTWrapper {
// Convert back to std Java interface
return rsaPublicJWK.toRSAPublicKey();
}
/**
* Create a token with the provided elements
* @param userID UniqueId of the USER (global unique ID)
@ -136,81 +177,122 @@ public class JWTWrapper {
* @param timeOutInMunites Expiration of the token.
* @return the encoded token
*/
public static String generateJWToken(long userID, String userLogin, String isuer, String application, Map<String, Object> rights, int timeOutInMunites) {
public static String generateJWToken(final long userID, final String userLogin, final String isuer, final String application, final Map<String, Object> rights, final int timeOutInMunites) {
if (rsaJWK == null) {
logger.warn("JWT private key is not present !!!");
LOGGER.warn("JWT private key is not present !!!");
return null;
}
/*
logger.debug(" ===> expire in : " + timeOutInMunites);
logger.debug(" ===>" + new Date().getTime());
logger.debug(" ===>" + new Date(new Date().getTime()));
logger.debug(" ===>" + new Date(new Date().getTime() - 60 * timeOutInMunites * 1000));
LOGGER.debug(" ===> expire in : " + timeOutInMunites);
LOGGER.debug(" ===>" + new Date().getTime());
LOGGER.debug(" ===>" + new Date(new Date().getTime()));
LOGGER.debug(" ===>" + new Date(new Date().getTime() - 60 * timeOutInMunites * 1000));
*/
try {
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);
logger.warn("timeOutInMunites= {}", timeOutInMunites);
Date now = new Date();
logger.warn("now = {}", now);
Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
logger.warn("expiration= {}", expiration);
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
final JWSSigner signer = new RSASSASigner(rsaJWK);
LOGGER.warn("timeOutInMunites= {}", timeOutInMunites);
final Date now = new Date();
LOGGER.warn("now = {}", now);
final Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
LOGGER.warn("expiration= {}", expiration);
final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
// add right if needed:
if (rights != null && !rights.isEmpty()) {
builder.claim("right", rights);
}
// Prepare JWT with claims set
JWTClaimsSet claimsSet = builder.build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
final JWTClaimsSet claimsSet = builder.build();
final 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) {
} catch (final JOSEException ex) {
ex.printStackTrace();
}
return null;
}
public static JWTClaimsSet validateToken(String signedToken, String isuer, String application) {
if (rsaPublicJWK == null) {
logger.warn("JWT public key is not present !!!");
return null;
}
public static JWTClaimsSet validateToken(final String signedToken, final String isuer, final String application) {
try {
// On the consumer side, parse the JWS and verify its RSA signature
SignedJWT signedJWT = SignedJWT.parse(signedToken);
final SignedJWT signedJWT = SignedJWT.parse(signedToken);
JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
if (!signedJWT.verify(verifier)) {
logger.error("JWT token is NOT verified ");
return null;
if (rsaPublicJWK == null) {
LOGGER.warn("JWT public key is not present !!!");
if (!ConfigBaseVariable.getTestMode()) {
return null;
}
final String rawSignature = signedJWT.getSigningInput().toString();
if (rawSignature.equals(TestSigner.test_signature)) {
// Test token : .application..
} else {
return null;
}
} else {
final JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
if (!signedJWT.verify(verifier)) {
LOGGER.error("JWT token is NOT verified ");
return null;
}
}
if (!new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime())) {
logger.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime());
LOGGER.error("JWT token is expired now = " + new Date() + " with=" + signedJWT.getJWTClaimsSet().getExpirationTime());
return null;
}
if (!isuer.equals(signedJWT.getJWTClaimsSet().getIssuer())) {
logger.error("JWT issuer is wong: '" + isuer + "' != '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
LOGGER.error("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 ...
//logger.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'");
//logger.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
//LOGGER.debug("JWT token is verified 'alice' =?= '" + signedJWT.getJWTClaimsSet().getSubject() + "'");
//LOGGER.debug("JWT token isuer 'https://c2id.com' =?= '" + signedJWT.getJWTClaimsSet().getIssuer() + "'");
return signedJWT.getJWTClaimsSet();
} catch (JOSEException ex) {
} catch (final JOSEException ex) {
ex.printStackTrace();
} catch (ParseException e) {
} catch (final ParseException e) {
e.printStackTrace();
}
return null;
}
public static String createJwtTestToken(final long userID, final String userLogin, final String isuer, final String application, final Map<String, Object> rights) {
if (!ConfigBaseVariable.getTestMode()) {
LOGGER.error("Test mode disable !!!!!");
return null;
}
try {
final int timeOutInMunites = 3600 * 24 * 31;
final Date now = new Date();
final Date expiration = new Date(new Date().getTime() - 60 * timeOutInMunites * 1000 /* millisecond */);
final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder().subject(Long.toString(userID)).claim("login", userLogin).claim("application", application).issuer(isuer).issueTime(now)
.expirationTime(expiration); // Do not ask why we need a "-" here ... this have no meaning
// add right if needed:
if (rights != null && !rights.isEmpty()) {
builder.claim("right", rights);
}
// Prepare JWT with claims set
final JWTClaimsSet claimsSet = builder.build();
final SignedJWT signedJWT = new SignedJWT(new JWSHeader.Builder(JWSAlgorithm.RS256).type(JOSEObjectType.JWT)/*.keyID(rsaJWK.getKeyID())*/.build(), claimsSet);
// Compute the RSA signature
signedJWT.sign(new TestSigner());
// serialize the output...
return signedJWT.serialize();
} catch (final Exception ex) {
LOGGER.error("Can not generate Test Token...");
}
return null;
}
}

View File

@ -148,7 +148,7 @@ public class TestTypes {
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.doubleData);
Assertions.assertEquals(insertedData.doubleData, retrieve.doubleData);
DataAccess.delete(TypesTable.class, insertedData.id);
}
@ -347,4 +347,123 @@ public class TestTypes {
DataAccess.delete(TypesTable.class, insertedData.id);
}
@Order(14)
@Test
public void testTextUpdateDirect() throws Exception {
final TypesTable test = new TypesTable();
test.textData = "test 1";
test.booleanData = null;
test.varcharData = "plop";
final TypesTable insertedData = DataAccess.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
// Try to retrieve all the data:
final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.textData);
Assertions.assertEquals(insertedData.textData, retrieve.textData);
Assertions.assertNull(retrieve.booleanData);
Assertions.assertNotNull(retrieve.varcharData);
Assertions.assertEquals(insertedData.varcharData, retrieve.varcharData);
// Update the text value:
retrieve.textData = "test 2";
retrieve.booleanData = true;
retrieve.varcharData = null;
final int nbUpdate = DataAccess.update(retrieve, insertedData.id);
Assertions.assertEquals(1, nbUpdate);
// Get new data
final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id);
Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id);
Assertions.assertNotNull(retrieve2.textData);
Assertions.assertEquals(retrieve.textData, retrieve2.textData);
Assertions.assertNotNull(retrieve2.booleanData);
Assertions.assertEquals(retrieve.booleanData, retrieve2.booleanData);
Assertions.assertNull(retrieve2.varcharData);
// test filter values:
retrieve.textData = "test 3";
retrieve.booleanData = false;
retrieve.varcharData = "test3";
final int nbUpdate2 = DataAccess.update(retrieve, insertedData.id, List.of("textData"));
Assertions.assertEquals(1, nbUpdate2);
// Get new data
final TypesTable retrieve3 = DataAccess.get(TypesTable.class, insertedData.id);
Assertions.assertNotNull(retrieve3);
Assertions.assertNotNull(retrieve3.id);
Assertions.assertEquals(insertedData.id, retrieve3.id);
Assertions.assertNotNull(retrieve3.textData);
Assertions.assertEquals(retrieve.textData, retrieve3.textData);
Assertions.assertNotNull(retrieve3.booleanData);
// note: retreive2
Assertions.assertEquals(retrieve2.booleanData, retrieve3.booleanData);
Assertions.assertNull(retrieve3.varcharData);
DataAccess.delete(TypesTable.class, insertedData.id);
}
@Order(15)
@Test
public void testTextUpdateJson() throws Exception {
final TypesTable test = new TypesTable();
test.textData = "test 1";
test.booleanData = null;
test.varcharData = "plop";
final TypesTable insertedData = DataAccess.insert(test);
Assertions.assertNotNull(insertedData);
Assertions.assertNotNull(insertedData.id);
Assertions.assertTrue(insertedData.id >= 0);
// Try to retrieve all the data:
final TypesTable retrieve = DataAccess.get(TypesTable.class, insertedData.id);
Assertions.assertNotNull(retrieve);
Assertions.assertNotNull(retrieve.id);
Assertions.assertEquals(insertedData.id, retrieve.id);
Assertions.assertNotNull(retrieve.textData);
Assertions.assertEquals(insertedData.textData, retrieve.textData);
Assertions.assertNull(retrieve.booleanData);
Assertions.assertNotNull(retrieve.varcharData);
Assertions.assertEquals(insertedData.varcharData, retrieve.varcharData);
// Update the text value:
final String jsonData = """
{
"textData": "test 2",
"booleanData": true,
"varcharData": null
}
""";
final int nbUpdate = DataAccess.updateWithJson(TypesTable.class, insertedData.id, jsonData);
Assertions.assertEquals(1, nbUpdate);
// Get new data
final TypesTable retrieve2 = DataAccess.get(TypesTable.class, insertedData.id);
Assertions.assertNotNull(retrieve2);
Assertions.assertNotNull(retrieve2.id);
Assertions.assertEquals(insertedData.id, retrieve2.id);
Assertions.assertNotNull(retrieve2.textData);
Assertions.assertEquals(retrieve.textData, retrieve2.textData);
Assertions.assertNotNull(retrieve2.booleanData);
Assertions.assertEquals(retrieve.booleanData, retrieve2.booleanData);
Assertions.assertNull(retrieve2.varcharData);
DataAccess.delete(TypesTable.class, insertedData.id);
}
}