forked from gCubeSystem/common-smartgears-legacy
- use of AccessTokenProvider
- use gcube-jackson instead of minimal-json for access token parsing [#21097]
This commit is contained in:
parent
e27784741b
commit
64c3f02996
|
@ -2,6 +2,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
||||||
|
|
||||||
# Changelog for Common Smartgears
|
# Changelog for Common Smartgears
|
||||||
|
|
||||||
|
## [v3.1.0] - 2021-05-14
|
||||||
|
|
||||||
|
- use of AccessTokenProvider
|
||||||
|
- use gcube-jackson instead of minimal-json for access token parsing [#21097]
|
||||||
|
|
||||||
|
|
||||||
## [v3.0.2] - 2020-03-01
|
## [v3.0.2] - 2020-03-01
|
||||||
|
|
||||||
- check if response is already committed on error
|
- check if response is already committed on error
|
||||||
|
|
24
pom.xml
24
pom.xml
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<groupId>org.gcube.core</groupId>
|
<groupId>org.gcube.core</groupId>
|
||||||
<artifactId>common-smartgears</artifactId>
|
<artifactId>common-smartgears</artifactId>
|
||||||
<version>3.0.2</version>
|
<version>3.1.0</version>
|
||||||
<name>SmartGears</name>
|
<name>SmartGears</name>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.distribution</groupId>
|
<groupId>org.gcube.distribution</groupId>
|
||||||
<artifactId>gcube-bom</artifactId>
|
<artifactId>gcube-bom</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>2.0.1</version>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
@ -41,11 +41,21 @@
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- gCube Jackson -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.eclipsesource.minimal-json</groupId>
|
<groupId>org.gcube.common</groupId>
|
||||||
<artifactId>minimal-json</artifactId>
|
<artifactId>gcube-jackson-databind</artifactId>
|
||||||
<version>0.9.4</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>gcube-jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>gcube-jackson-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- END gCube Jackson -->
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.gcube.common</groupId>
|
<groupId>org.gcube.common</groupId>
|
||||||
|
@ -189,7 +199,7 @@
|
||||||
<!-- excludes probe package from jar -->
|
<!-- excludes probe package from jar -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<!-- version>2.3.2</version -->
|
<!-- version>2.3.2</version -->
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>default-jar</id>
|
<id>default-jar</id>
|
||||||
|
@ -233,7 +243,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<!-- version>2.15</version -->
|
<!-- version>2.15</version -->
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- tomcat annotation discovery won't work with the default manifest-only
|
<!-- tomcat annotation discovery won't work with the default manifest-only
|
||||||
jar -->
|
jar -->
|
||||||
|
|
|
@ -6,19 +6,16 @@ import static org.gcube.smartgears.Constants.token_header;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.internal_server_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.internal_server_error;
|
||||||
import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error;
|
import static org.gcube.smartgears.handlers.application.request.RequestError.invalid_request_error;
|
||||||
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
|
|
||||||
|
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
|
import org.gcube.common.authorization.client.exceptions.ObjectNotFound;
|
||||||
import org.gcube.common.authorization.library.AuthorizationEntry;
|
import org.gcube.common.authorization.library.AuthorizationEntry;
|
||||||
|
import org.gcube.common.authorization.library.provider.AccessTokenProvider;
|
||||||
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
||||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||||
import org.gcube.common.authorization.library.provider.UmaJWTProvider;
|
|
||||||
import org.gcube.common.authorization.library.provider.UserInfo;
|
import org.gcube.common.authorization.library.provider.UserInfo;
|
||||||
import org.gcube.common.authorization.library.utils.Caller;
|
import org.gcube.common.authorization.library.utils.Caller;
|
||||||
import org.gcube.common.scope.api.ScopeProvider;
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
|
@ -27,13 +24,10 @@ import org.gcube.smartgears.Constants;
|
||||||
import org.gcube.smartgears.handlers.application.RequestEvent;
|
import org.gcube.smartgears.handlers.application.RequestEvent;
|
||||||
import org.gcube.smartgears.handlers.application.RequestHandler;
|
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||||
import org.gcube.smartgears.handlers.application.ResponseEvent;
|
import org.gcube.smartgears.handlers.application.ResponseEvent;
|
||||||
|
import org.gcube.smartgears.utils.GcubeJwt;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.eclipsesource.json.Json;
|
|
||||||
import com.eclipsesource.json.JsonArray;
|
|
||||||
import com.eclipsesource.json.JsonObject;
|
|
||||||
|
|
||||||
@XmlRootElement(name = Constants.request_context_retriever)
|
@XmlRootElement(name = Constants.request_context_retriever)
|
||||||
public class RequestContextRetriever extends RequestHandler {
|
public class RequestContextRetriever extends RequestHandler {
|
||||||
|
|
||||||
|
@ -55,46 +49,50 @@ public class RequestContextRetriever extends RequestHandler {
|
||||||
|
|
||||||
String authHeader = call.request().getHeader(Constants.authorization_header);
|
String authHeader = call.request().getHeader(Constants.authorization_header);
|
||||||
|
|
||||||
log.trace("auth header is {}",authHeader);
|
log.trace("authorization header is {}",authHeader);
|
||||||
|
log.trace("token header is {}",token);
|
||||||
|
log.trace("scope header is {}",scope);
|
||||||
|
|
||||||
String umaToken = null;
|
String retrievedUser = null;
|
||||||
|
String accessToken = null;
|
||||||
if (authHeader!=null && !authHeader.isEmpty()) {
|
if (authHeader!=null && !authHeader.isEmpty()) {
|
||||||
if (authHeader.startsWith(BEARER_AUTH_PREFIX))
|
if (authHeader.startsWith(BEARER_AUTH_PREFIX))
|
||||||
umaToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim();
|
accessToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim();
|
||||||
else if (token==null && authHeader.startsWith(BASIC_AUTH_PREFIX)) {
|
else if (token==null && authHeader.startsWith(BASIC_AUTH_PREFIX)) {
|
||||||
String basicAuthToken = authHeader.substring(BASIC_AUTH_PREFIX.length()).trim();
|
String basicAuthToken = authHeader.substring(BASIC_AUTH_PREFIX.length()).trim();
|
||||||
String decodedAuth = new String(Base64.getDecoder().decode(basicAuthToken.getBytes()));
|
String decodedAuth = new String(Base64.getDecoder().decode(basicAuthToken.getBytes()));
|
||||||
token = decodedAuth.split(":")[1];
|
String[] splitAuth = decodedAuth.split(":");
|
||||||
|
token = splitAuth[1];
|
||||||
|
retrievedUser = splitAuth[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Gives priority to the umaToken
|
||||||
|
if (accessToken!=null) {
|
||||||
|
this.retreiveAndSetInfoUmaToken(accessToken, token, call);
|
||||||
//Gives priority to the token
|
|
||||||
if (umaToken!=null) {
|
|
||||||
this.retreiveAndSetInfoUmaToken(umaToken, token, call);
|
|
||||||
} else if (token!=null)
|
} else if (token!=null)
|
||||||
this.retreiveAndSetInfoGcubeToken(token, call);
|
this.retreiveAndSetInfoGcubeToken(token, retrievedUser, call);
|
||||||
else if (scope!=null)
|
else if (scope!=null)
|
||||||
ScopeProvider.instance.set(scope);
|
ScopeProvider.instance.set(scope);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResponse(ResponseEvent e) {
|
public void handleResponse(ResponseEvent e) {
|
||||||
SecurityTokenProvider.instance.reset();
|
SecurityTokenProvider.instance.reset();
|
||||||
AuthorizationProvider.instance.reset();
|
AuthorizationProvider.instance.reset();
|
||||||
UmaJWTProvider.instance.reset();
|
AccessTokenProvider.instance.reset();
|
||||||
ScopeProvider.instance.reset();
|
ScopeProvider.instance.reset();
|
||||||
log.debug("resetting all the Thread local for this call.");
|
log.debug("resetting all the Thread local for this call.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retreiveAndSetInfoGcubeToken(String token, RequestEvent call){
|
private void retreiveAndSetInfoGcubeToken(String token, String retrievedUser, RequestEvent call){
|
||||||
log.trace("retrieving context using token {} ", token);
|
log.trace("retrieving context using token {} ", token);
|
||||||
AuthorizationEntry authEntry = null;
|
AuthorizationEntry authEntry = null;
|
||||||
try{
|
try{
|
||||||
authEntry = authorizationService().get(token);
|
authEntry = authorizationService().get(token);
|
||||||
|
if (retrievedUser != null && authEntry.getClientInfo().getId().equals(retrievedUser))
|
||||||
|
throw new Exception("user and token owner are not the same");
|
||||||
}catch(ObjectNotFound onf){
|
}catch(ObjectNotFound onf){
|
||||||
log.warn("rejecting call to {}, invalid token {}",call.context().name(),token);
|
log.warn("rejecting call to {}, invalid token {}",call.context().name(),token);
|
||||||
invalid_request_error.fire(call.context().name()+" invalid token : "+token);
|
invalid_request_error.fire(call.context().name()+" invalid token : "+token);
|
||||||
|
@ -109,50 +107,44 @@ public class RequestContextRetriever extends RequestHandler {
|
||||||
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext());
|
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void retreiveAndSetInfoUmaToken(String umaToken, String gcubeToken, RequestEvent call){
|
private void retreiveAndSetInfoUmaToken(String accessToken, String gcubeToken, RequestEvent call){
|
||||||
log.debug("using UMA token for authorization");
|
log.debug("using UMA token for authorization");
|
||||||
log.trace("retrieving context using uma token {} ", umaToken);
|
log.trace("retrieving context using uma token {} ", accessToken);
|
||||||
|
|
||||||
UmaJWTProvider.instance.set(umaToken);
|
AccessTokenProvider.instance.set(accessToken);
|
||||||
SecurityTokenProvider.instance.set(gcubeToken);
|
SecurityTokenProvider.instance.set(gcubeToken);
|
||||||
parseUmaTokenAndSet(umaToken);
|
parseAccessTokenAndSet(accessToken);
|
||||||
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get());
|
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseUmaTokenAndSet(String umaToken) {
|
private void parseAccessTokenAndSet(String umaToken) {
|
||||||
|
|
||||||
String realUmaTokenEncoded = umaToken.split("\\.")[1];
|
String realUmaTokenEncoded = umaToken.split("\\.")[1];
|
||||||
|
|
||||||
String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes()));
|
String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes()));
|
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
JsonObject object = Json.parse(realUmaToken).asObject();
|
|
||||||
String username = object.get("preferred_username").asString();
|
|
||||||
|
|
||||||
String scope = object.getString("aud", null);
|
GcubeJwt jwt = null;
|
||||||
|
try {
|
||||||
log.trace("token related context is {}", scope);
|
jwt = mapper.readValue(realUmaToken, GcubeJwt.class);
|
||||||
|
}catch(Exception e){
|
||||||
JsonObject resource = object.get("resource_access").asObject();
|
log.error("error decoding uma token",e);
|
||||||
|
internal_server_error.fire("error parsing access token");
|
||||||
log.trace("resource access is {}", resource.toString());
|
}
|
||||||
|
|
||||||
JsonObject scopeObject = resource.get(scope).asObject();
|
|
||||||
|
|
||||||
ScopeBean scopeBean = null;
|
ScopeBean scopeBean = null;
|
||||||
try {
|
try {
|
||||||
String decodedName = URLDecoder.decode(scope, StandardCharsets.UTF_8.toString());
|
scopeBean = new ScopeBean(jwt.getContext());
|
||||||
scopeBean = new ScopeBean(decodedName);
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
log.error("error decoding uma token",e);
|
log.error("error decoding uma token",e);
|
||||||
internal_server_error.fire("error contacting authorization service");
|
internal_server_error.fire("invalid context in access token");
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonArray roles = scopeObject.get("roles").asArray();
|
|
||||||
|
|
||||||
List<String> userRoles = new ArrayList<String>();
|
|
||||||
roles.forEach((e)->userRoles.add(e.asString()));
|
|
||||||
|
|
||||||
AuthorizationProvider.instance.set(new Caller(new UserInfo(username, userRoles), "token"));
|
AuthorizationProvider.instance.set(new Caller(new UserInfo(jwt.getUsername(), jwt.getRoles(), jwt.getEmail(), jwt.getFirstName(), jwt.getLastName()), "token"));
|
||||||
|
|
||||||
ScopeProvider.instance.set(scopeBean.toString());
|
ScopeProvider.instance.set(scopeBean.toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package org.gcube.smartgears.utils;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class GcubeJwt {
|
||||||
|
|
||||||
|
@JsonProperty("aud")
|
||||||
|
private String context;
|
||||||
|
|
||||||
|
@JsonProperty("resource_access")
|
||||||
|
private Map<String, Roles> contextAccess = new HashMap<>();
|
||||||
|
|
||||||
|
@JsonProperty("preferred_username")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@JsonProperty("given_name")
|
||||||
|
private String firstName;
|
||||||
|
|
||||||
|
@JsonProperty("family_name")
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
@JsonProperty("email")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
public List<String> getRoles(){
|
||||||
|
return contextAccess.get(this.context).roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContext() {
|
||||||
|
try {
|
||||||
|
return URLDecoder.decode(context, StandardCharsets.UTF_8.toString());
|
||||||
|
}catch (UnsupportedEncodingException e) {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "GcubeJwt [context=" + getContext() + ", roles=" + getRoles() + ", username=" + username
|
||||||
|
+ ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Roles {
|
||||||
|
|
||||||
|
@JsonProperty("roles")
|
||||||
|
List<String> roles = new ArrayList<>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue