jwt decode service

This commit is contained in:
Alfredo Oliviero 2024-03-26 17:31:57 +01:00
parent 365716ba77
commit 745e3b7425
4 changed files with 164 additions and 2 deletions

View File

@ -5,4 +5,6 @@ description: Identity Manager Service
excludes:
- path: /excluded
- path: /guest
- path: /api-docs/*
- path: /jwt/decode
- path: /jwt/introspection
- path: /api-docs/*

14
pom.xml
View File

@ -91,6 +91,20 @@
<version>2.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<!--
usermanagement-core depends on older httpcommon and gives this error on keycloak client:
java.lang.NoClassDefFoundError: org/apache/http/ssl/TrustStrategy

View File

@ -0,0 +1,127 @@
package org.gcube.service.idm.rest;
import java.util.HashMap;
import java.util.Map;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.slf4j.LoggerFactory;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@Path("jwt")
public class JwtService {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JwtService.class);
public static Map<String, Object> decodeJwtToken(String token)
throws JsonMappingException, JsonProcessingException {
DecodedJWT decodedJWT = JWT.decode(token);
String headerJson = ContextSerializator.decodeBase64String(decodedJWT.getHeader());
String payloadJson = ContextSerializator.decodeBase64String(decodedJWT.getPayload());
// String signatureJson =
// ContextSerializator.decodeBase64String(decodedJWT.getSignature());
Map<String, Object> decoded = new HashMap<String, Object>();
decoded.put("jwt_token", token);
decoded.put("token", decodedJWT.getToken());
decoded.put("header", ContextSerializator.jsonStringToHasmap(headerJson));
decoded.put("payload", ContextSerializator.jsonStringToHasmap(payloadJson));
// decoded.put("signature",
// ContextSerializator.jsonStringToHasmap(signatureJson));
decoded.put("decodedJWT", decodedJWT);
return decoded;
}
@GET
@Path("/decode")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getDecodedJwtToken(
@QueryParam("token") String token) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> decoded = decodeJwtToken(token);
responseBean.setResult(decoded);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JWTDecodeException e) {
e.printStackTrace();
logger.error("error decoding the token", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
catch (Exception e) {
logger.error("error processing the decoding request", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
}
@GET
@Path("/auth")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getDecodedJwtAuth() {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
Map<String, String> authorizations = SecretManagerProvider.get().getHTTPAuthorizationHeaders();
String token = authorizations.get("Authorization").replace("Bearer", "").trim();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> response = new HashMap<String, Object>();
response.put("auth_token", decodeJwtToken(token));
// response.put("authorizations", authorizations);
responseBean.setResult(response);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JWTDecodeException e) {
e.printStackTrace();
logger.error("error decoding the token", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
catch (Exception e) {
e.printStackTrace();
logger.error("error processing the decoding request", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
}
}

View File

@ -1,11 +1,19 @@
package org.gcube.service.idm.serializers;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import org.gcube.smartgears.configuration.container.ContainerConfiguration;
import org.gcube.smartgears.context.container.ContainerContext;
import org.gcube.smartgears.security.SimpleCredentials;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
/**
* Jackson Serialization utils for Smartgear Context classes
@ -17,6 +25,16 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
public class ContextSerializator {
private static ObjectMapper serializer = null;
protected static TypeReference<HashMap<String,Object>> typeRefHashmap = new TypeReference<HashMap<String,Object>>() {};
public static String decodeBase64String(String encodedString){
return new String(Base64.getUrlDecoder().decode(encodedString), StandardCharsets.UTF_8);
}
public static HashMap<String, Object> jsonStringToHasmap(String jsonString) throws JsonMappingException, JsonProcessingException {
return getSerializer().readValue(jsonString, typeRefHashmap);
}
public static ObjectMapper getSerializer() {
if (serializer == null) {
ObjectMapper om = new ObjectMapper();
@ -27,7 +45,8 @@ public class ContextSerializator {
module.addSerializer(ContainerContext.class, new ContainerContextSerializer());
module.addSerializer(SimpleCredentials.class, new SimpleCredentialsSerializer());
om.registerModule(module);
// DecodedJWT serialization
om.registerModule(new JavaTimeModule());
serializer = om;
}
return serializer;