diff --git a/pom.xml b/pom.xml index cac27e0..528aeaa 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,13 @@ org.gcube.common keycloak-client + + + com.auth0 + java-jwt + 4.4.0 + + org.gcube.common common-security diff --git a/src/main/java/org/gcube/common/security/secrets/AccessTokenSecret.java b/src/main/java/org/gcube/common/security/secrets/AccessTokenSecret.java index 37da489..759546a 100644 --- a/src/main/java/org/gcube/common/security/secrets/AccessTokenSecret.java +++ b/src/main/java/org/gcube/common/security/secrets/AccessTokenSecret.java @@ -76,9 +76,10 @@ public class AccessTokenSecret extends Secret { } @Override - public boolean isExpired() { - return false; + public boolean isValid() { + if (this.umaTokenSecret.isExpired()) + refreshAccessToken(); + return this.umaTokenSecret.isValid(); } - } \ No newline at end of file diff --git a/src/main/java/org/gcube/common/security/secrets/CredentialSecret.java b/src/main/java/org/gcube/common/security/secrets/CredentialSecret.java index 5c17835..7d0386a 100644 --- a/src/main/java/org/gcube/common/security/secrets/CredentialSecret.java +++ b/src/main/java/org/gcube/common/security/secrets/CredentialSecret.java @@ -58,7 +58,7 @@ public class CredentialSecret extends Secret { } @Override - public boolean isExpired() { - return false; + public boolean isValid() { + return this.accessTokenSecret.isValid(); } } diff --git a/src/main/java/org/gcube/common/security/secrets/GCubeJWTObject.java b/src/main/java/org/gcube/common/security/secrets/GCubeJWTObject.java index 06a0dc0..721b19a 100644 --- a/src/main/java/org/gcube/common/security/secrets/GCubeJWTObject.java +++ b/src/main/java/org/gcube/common/security/secrets/GCubeJWTObject.java @@ -52,6 +52,10 @@ public class GCubeJWTObject { @JsonProperty("email") private String email; + @JsonProperty("exp") + private long expirationTime; + + public List getRoles(){ return contextAccess.get(this.context) == null ? MINIMAL_ROLES : contextAccess.get(this.context).roles; } @@ -84,6 +88,11 @@ public class GCubeJWTObject { public String getEmail() { return email; } + + public long getExpirationTime() { + return expirationTime; + } + @Override public String toString() { return "GcubeJwt [context=" + getContext() + ", roles=" + getRoles() + ", username=" + username diff --git a/src/main/java/org/gcube/common/security/secrets/GCubeSecret.java b/src/main/java/org/gcube/common/security/secrets/GCubeSecret.java index e1d0048..a59648c 100644 --- a/src/main/java/org/gcube/common/security/secrets/GCubeSecret.java +++ b/src/main/java/org/gcube/common/security/secrets/GCubeSecret.java @@ -22,10 +22,6 @@ public class GCubeSecret extends Secret { private String context; public GCubeSecret(String gcubeToken) { - if( gcubeToken == null || gcubeToken.isEmpty()) - throw new IllegalArgumentException("Invalid token: is null or empty"); - if(!Pattern.matches(GCUBE_TOKEN_REGEX, gcubeToken)) - throw new IllegalArgumentException("Invalid token: the gCube token must comply with the regex " + GCUBE_TOKEN_REGEX); this.gcubeToken = gcubeToken; } @@ -37,6 +33,8 @@ public class GCubeSecret extends Secret { this.context = authorizationEntry.getContext(); } + + @Override public Owner getOwner() { @@ -70,8 +68,8 @@ public class GCubeSecret extends Secret { } @Override - public boolean isExpired() { - return false; + public boolean isValid() { + return gcubeToken != null && !gcubeToken.isEmpty() && Pattern.matches(GCUBE_TOKEN_REGEX, gcubeToken); } } diff --git a/src/main/java/org/gcube/common/security/secrets/UmaTokenSecret.java b/src/main/java/org/gcube/common/security/secrets/UmaTokenSecret.java index c0fd115..929f07c 100644 --- a/src/main/java/org/gcube/common/security/secrets/UmaTokenSecret.java +++ b/src/main/java/org/gcube/common/security/secrets/UmaTokenSecret.java @@ -5,11 +5,19 @@ import java.util.HashMap; import java.util.Map; import org.gcube.com.fasterxml.jackson.databind.ObjectMapper; +import org.gcube.common.keycloak.KeycloakClient; +import org.gcube.common.keycloak.KeycloakClientFactory; import org.gcube.common.keycloak.model.AccessToken; +import org.gcube.common.keycloak.model.ModelUtils; +import org.gcube.common.keycloak.model.PublishedRealmRepresentation; import org.gcube.common.security.Owner; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class UmaTokenSecret extends Secret { + private static final Logger log = LoggerFactory.getLogger(UmaTokenSecret.class); + private static final String AUTH_HEADER = "Authorization"; private static final String USER_HEADER = "d4s-user"; @@ -52,8 +60,6 @@ public class UmaTokenSecret extends Secret { return encodedUmaToken; } - - @Override public boolean isExpired() { init(); return accessToken.isExpired(); @@ -68,17 +74,16 @@ public class UmaTokenSecret extends Secret { String decodedAccessPart = new String(Base64.getDecoder().decode(realAccessTokenEncoded.getBytes())); ObjectMapper objectMapper = new ObjectMapper(); - + this.accessToken = objectMapper.readValue(decodedAccessPart, AccessToken.class); GCubeJWTObject obj = objectMapper.readValue(decodedAccessPart, GCubeJWTObject.class); - owner = new Owner(obj.getUsername(), obj.getRoles(), obj.getEmail(), obj.getFirstName(), obj.getLastName(), obj.isExternalService(), obj.isApplication()); + owner = new Owner(obj.getUsername(), obj.getRoles(), obj.getEmail(), obj.getFirstName(), + obj.getLastName(), obj.isExternalService(), obj.isApplication()); owner.setClientName(obj.getClientName()); owner.setContactOrganisation(obj.getContactOrganisation()); owner.setClientName(obj.getClientName()); context = obj.getContext(); - - initialised = true; } catch (Exception e) { throw new RuntimeException(e); @@ -86,4 +91,18 @@ public class UmaTokenSecret extends Secret { } + @Override + public boolean isValid() { + init(); + try { + KeycloakClient client = KeycloakClientFactory.newInstance(); + PublishedRealmRepresentation realmInfo = client.getRealmInfo(client.getRealmBaseURL(context)); + return ModelUtils.isValid(encodedUmaToken, realmInfo.getPublicKey()); + }catch (Exception e) { + log.error("Error contacting keycloak, is not possible to check token validity",e); + return false; + } + } + + }