From a4462eb3256406dd227475aa7ed2950a8193c440 Mon Sep 17 00:00:00 2001 From: Lucio Date: Wed, 18 Nov 2020 18:50:49 +0100 Subject: [PATCH] commit for new IAM release --- pom.xml | 9 +- .../gcube/smartgears/configuration/Mode.java | 3 +- .../lifecycle/ProfilePublisher.java | 25 +++-- .../request/RequestAccounting.java | 1 + .../request/RequestContextRetriever.java | 106 +++++++++++++++--- .../application/request/RequestValidator.java | 15 +-- .../container/lifecycle/ProfilePublisher.java | 25 +++-- 7 files changed, 136 insertions(+), 48 deletions(-) diff --git a/pom.xml b/pom.xml index e5e2ad5..589b043 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.gcube.core common-smartgears - 2.2.0 + 2.3.0-SNAPSHOT SmartGears @@ -41,6 +41,12 @@ + + com.eclipsesource.minimal-json + minimal-json + 0.9.4 + + org.gcube.common authorization-client @@ -165,7 +171,6 @@ ch.qos.logback logback-classic - 1.2.3 runtime diff --git a/src/main/java/org/gcube/smartgears/configuration/Mode.java b/src/main/java/org/gcube/smartgears/configuration/Mode.java index c02b97a..a30030e 100644 --- a/src/main/java/org/gcube/smartgears/configuration/Mode.java +++ b/src/main/java/org/gcube/smartgears/configuration/Mode.java @@ -8,5 +8,6 @@ package org.gcube.smartgears.configuration; */ public enum Mode { online, - offline + offline, + root } \ No newline at end of file diff --git a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisher.java b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisher.java index 03f60ad..24521ea 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisher.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/lifecycle/ProfilePublisher.java @@ -12,6 +12,7 @@ import org.gcube.common.authorization.client.proxy.AuthorizationProxy; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.resources.gcore.GCoreEndpoint; import org.gcube.informationsystem.publisher.ScopedPublisher; +import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.provider.ProviderFactory; import org.slf4j.Logger; @@ -78,21 +79,23 @@ public class ProfilePublisher { SecurityTokenProvider.instance.set(previousToken); } */ - + ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + log.debug("using context {}",contextCL.getClass().getSimpleName()); + String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.container().configuration().mode()!=Mode.root) Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.create(profile, resolveScopesFromTokens(tokens)); } catch (Exception e) { rethrowUnchecked(e); } finally{ SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.container().configuration().mode()!=Mode.root) Thread.currentThread().setContextClassLoader(contextCL); } sharePublished(profile); @@ -129,19 +132,23 @@ public class ProfilePublisher { ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + log.debug("using context {}",contextCL.getClass().getSimpleName()); + String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)context.configuration().startTokens().toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.container().configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.update(profile); } catch (Exception e) { rethrowUnchecked(e); } finally{ SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.container().configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(contextCL); } sharePublished(profile); @@ -178,18 +185,22 @@ public class ProfilePublisher { ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); + log.debug("using context {}",contextCL.getClass().getSimpleName()); + String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.container().configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.remove(profile, resolveScopesFromTokens(tokens)); } catch (Exception e) { rethrowUnchecked(e); } finally{ SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.container().configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(contextCL); } log.debug("after remove application profile contains scopes {}",profile.scopes().asCollection()); sharePublished(profile); diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java index 69f6cc0..c7b3e9c 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestAccounting.java @@ -42,6 +42,7 @@ public class RequestAccounting extends RequestHandler { calledMethod = e.request().getRequestURI().substring(e.request().getContextPath().length()); if (calledMethod.isEmpty()) calledMethod = "/"; + calledMethod= e.request().getMethod()+" "+calledMethod; } InnerMethodName.instance.set(calledMethod); String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN"; diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java index f2f0d54..92af912 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestContextRetriever.java @@ -6,15 +6,23 @@ 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.invalid_request_error; -import javax.xml.bind.DatatypeConverter; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + import javax.xml.bind.annotation.XmlRootElement; import org.gcube.common.authorization.client.exceptions.ObjectNotFound; import org.gcube.common.authorization.library.AuthorizationEntry; import org.gcube.common.authorization.library.provider.AuthorizationProvider; 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.utils.Caller; import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.common.scope.impl.ScopeBean; import org.gcube.smartgears.Constants; import org.gcube.smartgears.handlers.application.RequestEvent; import org.gcube.smartgears.handlers.application.RequestHandler; @@ -22,6 +30,10 @@ import org.gcube.smartgears.handlers.application.ResponseEvent; import org.slf4j.Logger; 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) public class RequestContextRetriever extends RequestHandler { @@ -40,24 +52,30 @@ public class RequestContextRetriever extends RequestHandler { public void handleRequest(RequestEvent call) { String token = call.request().getParameter(token_header)==null? call.request().getHeader(token_header):call.request().getParameter(token_header); String scope = call.request().getParameter(scope_header)==null? call.request().getHeader(scope_header):call.request().getParameter(scope_header); - - if (token==null && call.request().getHeader(Constants.authorization_header)!=null){ - - String authorization = call.request().getHeader(Constants.authorization_header); - - if (authorization.contains(BASIC_AUTH_PREFIX)) { - String base64Credentials = authorization.substring(BASIC_AUTH_PREFIX.length()).trim(); - String credentials = new String(DatatypeConverter.parseBase64Binary(base64Credentials)); - // credentials = username:password - final String[] values = credentials.split(":",2); - token = values[1]; - } else if (authorization.contains(BEARER_AUTH_PREFIX)) - token = authorization.substring(BEARER_AUTH_PREFIX.length()).trim(); + + String authHeader = call.request().getHeader(Constants.authorization_header); + + log.trace("auth header is {}",authHeader); + + String umaToken = null; + if (authHeader!=null && !authHeader.isEmpty()) { + if (authHeader.startsWith(BEARER_AUTH_PREFIX)) + umaToken = authHeader.substring(BEARER_AUTH_PREFIX.length()).trim(); + else if (token==null && authHeader.startsWith(BASIC_AUTH_PREFIX)) { + String basicAuthToken = authHeader.substring(BASIC_AUTH_PREFIX.length()).trim(); + String decodedAuth = new String(Base64.getDecoder().decode(basicAuthToken.getBytes())); + token = decodedAuth.split(":")[1]; + } } + + + //Gives priority to the token - if (token!=null) - this.retreiveAndSetInfo(token, call); + if (umaToken!=null) { + this.retreiveAndSetInfoUmaToken(umaToken, token, call); + } else if (token!=null) + this.retreiveAndSetInfoGcubeToken(token, call); else if (scope!=null) ScopeProvider.instance.set(scope); @@ -67,12 +85,13 @@ public class RequestContextRetriever extends RequestHandler { public void handleResponse(ResponseEvent e) { SecurityTokenProvider.instance.reset(); AuthorizationProvider.instance.reset(); + UmaJWTProvider.instance.reset(); ScopeProvider.instance.reset(); log.debug("resetting all the Thread local for this call."); } - private void retreiveAndSetInfo(String token, RequestEvent call){ - log.info("retrieving context using token {} ", token); + private void retreiveAndSetInfoGcubeToken(String token, RequestEvent call){ + log.trace("retrieving context using token {} ", token); AuthorizationEntry authEntry = null; try{ authEntry = authorizationService().get(token); @@ -89,4 +108,55 @@ public class RequestContextRetriever extends RequestHandler { ScopeProvider.instance.set(authEntry.getContext()); log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext()); } + + private void retreiveAndSetInfoUmaToken(String umaToken, String gcubeToken, RequestEvent call){ + log.debug("using UMA token for authorization"); + log.trace("retrieving context using uma token {} ", umaToken); + + UmaJWTProvider.instance.set(umaToken); + SecurityTokenProvider.instance.set(gcubeToken); + parseUmaTokenAndSet(umaToken); + log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), ScopeProvider.instance.get()); + } + + private void parseUmaTokenAndSet(String umaToken) { + + String realUmaTokenEncoded = umaToken.split("\\.")[1]; + + String realUmaToken = new String(Base64.getDecoder().decode(realUmaTokenEncoded.getBytes())); + + JsonObject object = Json.parse(realUmaToken).asObject(); + String username = object.get("preferred_username").asString(); + + String scope = object.getString("aud", null); + + log.trace("token related context is {}", scope); + + JsonObject resource = object.get("resource_access").asObject(); + + log.trace("resource access is {}", resource.toString()); + + JsonObject scopeObject = resource.get(scope).asObject(); + + ScopeBean scopeBean = null; + try { + String decodedName = URLDecoder.decode(scope, StandardCharsets.UTF_8.toString()); + scopeBean = new ScopeBean(decodedName); + }catch(Exception e){ + log.error("error decoding uma token",e); + internal_server_error.fire("error contacting authorization service"); + } + + JsonArray roles = scopeObject.get("roles").asArray(); + + List userRoles = new ArrayList(); + roles.forEach((e)->userRoles.add(e.asString())); + + AuthorizationProvider.instance.set(new Caller(new UserInfo(username, userRoles), "token")); + ScopeProvider.instance.set(scopeBean.toString()); + + } + + + } diff --git a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java index 115eff0..97d6955 100644 --- a/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java +++ b/src/main/java/org/gcube/smartgears/handlers/application/request/RequestValidator.java @@ -1,9 +1,7 @@ package org.gcube.smartgears.handlers.application.request; -import static org.gcube.common.authorization.client.Constants.authorizationService; import static org.gcube.smartgears.handlers.application.request.RequestError.application_failed_error; import static org.gcube.smartgears.handlers.application.request.RequestError.application_unavailable_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 java.io.IOException; @@ -11,12 +9,7 @@ import java.io.IOException; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; -import org.gcube.common.authorization.client.exceptions.ObjectNotFound; -import org.gcube.common.authorization.library.AuthorizationEntry; -import org.gcube.common.authorization.library.PolicyUtils; -import org.gcube.common.authorization.library.policies.Policy; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; -import org.gcube.common.authorization.library.provider.ServiceIdentifier; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.impl.ScopeBean; import org.gcube.common.scope.impl.ScopeBean.Type; @@ -25,7 +18,6 @@ import org.gcube.smartgears.configuration.container.ContainerConfiguration; import org.gcube.smartgears.context.application.ApplicationContext; import org.gcube.smartgears.handlers.application.RequestEvent; import org.gcube.smartgears.handlers.application.RequestHandler; -import org.gcube.smartgears.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,8 +50,8 @@ public class RequestValidator extends RequestHandler { validateScopeCall(); - if (SecurityTokenProvider.instance.get()!=null) - validatePolicy(SecurityTokenProvider.instance.get(), call); + /*if (SecurityTokenProvider.instance.get()!=null) + validatePolicy(SecurityTokenProvider.instance.get(), call);*/ } @@ -128,6 +120,7 @@ public class RequestValidator extends RequestHandler { return getName(); } + /* private void validatePolicy(String token, RequestEvent call){ log.info("accessing policy validator with token {} ", token); AuthorizationEntry authEntry = null; @@ -149,7 +142,7 @@ public class RequestValidator extends RequestHandler { invalid_request_error.fire("rejecting call to "+context.name()+": "+authEntry.getClientInfo().getId()+" is not allowed to contact the service"); } - } + }*/ diff --git a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisher.java b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisher.java index d3933ab..3c7eabf 100644 --- a/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisher.java +++ b/src/main/java/org/gcube/smartgears/handlers/container/lifecycle/ProfilePublisher.java @@ -11,6 +11,7 @@ import org.gcube.common.authorization.client.proxy.AuthorizationProxy; import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.resources.gcore.HostingNode; import org.gcube.informationsystem.publisher.ScopedPublisher; +import org.gcube.smartgears.configuration.Mode; import org.gcube.smartgears.context.container.ContainerContext; import org.gcube.smartgears.handlers.ProfileEvents; import org.gcube.smartgears.provider.ProviderFactory; @@ -88,18 +89,20 @@ public class ProfilePublisher { }*/ ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - + log.debug("using context {}",contextCL.getClass().getSimpleName()); String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.create(profile, resolveScopesFromTokens(tokens)); } catch (Exception e) { rethrowUnchecked(e); } finally { SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(contextCL); } sharePublished(profile); @@ -147,19 +150,21 @@ public class ProfilePublisher { log.debug("[update] resource scopes are : {} ",profile.scopes().asCollection()); ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - + log.debug("using context {}",contextCL.getClass().getSimpleName()); String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)context.configuration().startTokens().toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.update(profile); } catch (Exception e) { rethrowUnchecked(e); } finally { SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(contextCL); } sharePublished(profile); @@ -198,18 +203,20 @@ public class ProfilePublisher { } */ ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); - + log.debug("using context {}",contextCL.getClass().getSimpleName()); String previousToken = SecurityTokenProvider.instance.get(); try{//This classloader set is needed for the jaxb context if (previousToken==null) SecurityTokenProvider.instance.set((String)tokens.toArray()[0]); - Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(ProfilePublisher.class.getClassLoader()); profile = publisher.remove(profile, resolveScopesFromTokens(tokens)); } catch (Exception e) { rethrowUnchecked(e); } finally { SecurityTokenProvider.instance.set(previousToken); - Thread.currentThread().setContextClassLoader(contextCL); + if (context.configuration().mode()!=Mode.root) + Thread.currentThread().setContextClassLoader(contextCL); } log.debug("after remove container profile contains scopes {}",profile.scopes().asCollection());