merge for relese 4.6.1
git-svn-id: https://svn.d4science-ii.research-infrastructures.eu/gcube/branches/common/common-smartgears/2.1@151408 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
b06b505453
commit
a49c4de5dd
|
@ -1,4 +1,17 @@
|
|||
<ReleaseNotes>
|
||||
<Changeset component="common-smartgears-2.1.5" date="2017-07-18">
|
||||
<Change>Added ThreadLocal InnerMethodName to set method name from application</Change>
|
||||
</Changeset>
|
||||
<Changeset component="common-smartgears-2.1.4" date="2017-05-30">
|
||||
<Change>Validation handler for application split in 2 different handlers:
|
||||
- ContextRetriever that set Token and Scope
|
||||
- RequestValidation that does all the required checks
|
||||
</Change>
|
||||
</Changeset>
|
||||
<Changeset component="common-smartgears-2.1.3" date="2017-05-12">
|
||||
<Change>Added gcube bom dependency</Change>
|
||||
<Change>Search for handlers in the root classpath</Change>
|
||||
</Changeset>
|
||||
<Changeset component="common-smartgears-2.1.2" date="2017-03-22">
|
||||
<Change>Modified the Authorization filter to accept also children
|
||||
scope when authorizeChildrenContext is enabled on ContianerConfiguration</Change>
|
||||
|
|
Binary file not shown.
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
|
||||
<groupId>org.gcube.core</groupId>
|
||||
<artifactId>common-smartgears</artifactId>
|
||||
<version>2.1.3-SNAPSHOT</version>
|
||||
<version>2.1.5-SNAPSHOT</version>
|
||||
<name>SmartGears</name>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
|
@ -117,6 +117,11 @@ public class Constants {
|
|||
*/
|
||||
public static final String request_validation = "request-validation";
|
||||
|
||||
/**
|
||||
* The configuration name of {@link RequestValidator}s.
|
||||
*/
|
||||
public static final String request_context_retriever = "context-retriever";
|
||||
|
||||
|
||||
/**
|
||||
* The configuration name of {@link AccountingManager}s.
|
||||
|
|
|
@ -96,6 +96,7 @@ public class ProfilePublisher {
|
|||
}
|
||||
|
||||
sharePublished(profile);
|
||||
log.debug("shared profile with scopes {}", profile.scopes().asCollection());
|
||||
}
|
||||
|
||||
public void addToAll() {
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
|
|||
import org.gcube.accounting.persistence.AccountingPersistence;
|
||||
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
||||
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
|
||||
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
|
||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.gcube.smartgears.Constants;
|
||||
|
@ -17,6 +16,7 @@ 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.handlers.application.ResponseEvent;
|
||||
import org.gcube.smartgears.utils.InnerMethodName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -43,11 +43,11 @@ public class RequestAccounting extends RequestHandler {
|
|||
if (calledMethod.isEmpty())
|
||||
calledMethod = "/";
|
||||
}
|
||||
CalledMethodProvider.instance.set(calledMethod);
|
||||
InnerMethodName.instance.set(calledMethod);
|
||||
String caller = AuthorizationProvider.instance.get()!=null? AuthorizationProvider.instance.get().getClient().getId(): "UNKNOWN";
|
||||
startCallThreadLocal.set(System.currentTimeMillis());
|
||||
log.info("REQUEST START ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} ",
|
||||
context.configuration().name(),context.configuration().serviceClass(), CalledMethodProvider.instance.get(),
|
||||
context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(),
|
||||
caller, e.request().getRemoteHost(), ScopeProvider.instance.get());
|
||||
|
||||
}
|
||||
|
@ -73,10 +73,10 @@ public class RequestAccounting extends RequestHandler {
|
|||
generateAccounting(caller,callerQualifier,callerIp==null?"UNKNOWN":callerIp , context);
|
||||
|
||||
log.info("REQUEST SERVED ON {}:{}({}) CALLED FROM {}@{} IN SCOPE {} FINISHED IN {} millis",
|
||||
context.configuration().name(),context.configuration().serviceClass(), CalledMethodProvider.instance.get(),
|
||||
context.configuration().name(),context.configuration().serviceClass(), InnerMethodName.instance.get(),
|
||||
caller, callerIp, ScopeProvider.instance.get(), System.currentTimeMillis()-startCallThreadLocal.get());
|
||||
startCallThreadLocal.remove();
|
||||
CalledMethodProvider.instance.reset();
|
||||
InnerMethodName.instance.reset();
|
||||
if (resetScope)
|
||||
ScopeProvider.instance.reset();
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class RequestAccounting extends RequestHandler {
|
|||
serviceUsageRecord.setServiceName(context.configuration().name());
|
||||
|
||||
serviceUsageRecord.setHost(context.container().configuration().hostname()+":"+context.container().configuration().port());
|
||||
serviceUsageRecord.setCalledMethod(CalledMethodProvider.instance.get());
|
||||
serviceUsageRecord.setCalledMethod(InnerMethodName.instance.get());
|
||||
serviceUsageRecord.setCallerHost(remoteHost);
|
||||
serviceUsageRecord.setOperationResult(OperationResult.SUCCESS);
|
||||
serviceUsageRecord.setDuration(System.currentTimeMillis()-startCallThreadLocal.get());
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package org.gcube.smartgears.handlers.application.request;
|
||||
|
||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
||||
import static org.gcube.smartgears.Constants.oauth_secret;
|
||||
import static org.gcube.smartgears.Constants.scope_header;
|
||||
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 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.utils.Caller;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.gcube.smartgears.Constants;
|
||||
import org.gcube.smartgears.handlers.application.RequestEvent;
|
||||
import org.gcube.smartgears.handlers.application.RequestHandler;
|
||||
import org.gcube.smartgears.handlers.application.ResponseEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@XmlRootElement(name = Constants.request_context_retriever)
|
||||
public class RequestContextRetriever extends RequestHandler {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(RequestContextRetriever.class);
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return Constants.request_context_retriever;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 basicAuthorization = call.request().getHeader(Constants.authorization_header);
|
||||
String base64Credentials = basicAuthorization.substring("Basic".length()).trim();
|
||||
String credentials = new String(DatatypeConverter.parseBase64Binary(base64Credentials));
|
||||
// credentials = username:password
|
||||
final String[] values = credentials.split(":",2);
|
||||
token = values[1];
|
||||
}
|
||||
|
||||
if (token==null && scope==null && call.request().getParameter(oauth_secret)!=null)
|
||||
token = call.request().getParameter(oauth_secret);
|
||||
|
||||
//Gives priority to the token
|
||||
if (token!=null)
|
||||
this.retreiveAndSetInfo(token, call);
|
||||
else if (scope!=null)
|
||||
ScopeProvider.instance.set(scope);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResponse(ResponseEvent e) {
|
||||
SecurityTokenProvider.instance.reset();
|
||||
AuthorizationProvider.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);
|
||||
AuthorizationEntry authEntry = null;
|
||||
try{
|
||||
authEntry = authorizationService().get(token);
|
||||
}catch(ObjectNotFound onf){
|
||||
log.warn("rejecting call to {}, invalid token {}",call.context().name(),token);
|
||||
invalid_request_error.fire(call.context().name()+" invalid token : "+token);
|
||||
}catch(Exception e){
|
||||
log.error("error contacting authorization service",e);
|
||||
internal_server_error.fire("error contacting authorization service");
|
||||
}
|
||||
|
||||
AuthorizationProvider.instance.set(new Caller(authEntry.getClientInfo(), authEntry.getQualifier()));
|
||||
SecurityTokenProvider.instance.set(token);
|
||||
ScopeProvider.instance.set(authEntry.getContext());
|
||||
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext());
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
package org.gcube.smartgears.handlers.application.request;
|
||||
|
||||
import static org.gcube.common.authorization.client.Constants.authorizationService;
|
||||
import static org.gcube.smartgears.Constants.scope_header;
|
||||
import static org.gcube.smartgears.Constants.token_header;
|
||||
import static org.gcube.smartgears.Constants.oauth_secret;
|
||||
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;
|
||||
|
@ -11,7 +8,6 @@ import static org.gcube.smartgears.handlers.application.request.RequestError.inv
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
|
@ -19,12 +15,8 @@ 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.AuthorizationProvider;
|
||||
import org.gcube.common.authorization.library.provider.ClientInfo;
|
||||
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
|
||||
import org.gcube.common.authorization.library.provider.ServiceIdentifier;
|
||||
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.common.scope.impl.ScopeBean.Type;
|
||||
|
@ -33,7 +25,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.handlers.application.ResponseEvent;
|
||||
import org.gcube.smartgears.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -42,6 +33,7 @@ import org.slf4j.LoggerFactory;
|
|||
public class RequestValidator extends RequestHandler {
|
||||
|
||||
@XmlAttribute(required=false, name="oauth")
|
||||
@Deprecated
|
||||
boolean oauthCompatibility = false;
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(RequestValidator.class);
|
||||
|
@ -62,22 +54,15 @@ public class RequestValidator extends RequestHandler {
|
|||
|
||||
validateAgainstLifecycle(call);
|
||||
|
||||
if (!validateToken(call)){
|
||||
String scope = call.request().getParameter(scope_header)==null? call.request().getHeader(scope_header):call.request().getParameter(scope_header);
|
||||
validateScope(scope);
|
||||
log.info("received call to {} in context {}",call.uri(),scope);
|
||||
}
|
||||
rejectUnauthorizedCalls(call);
|
||||
|
||||
validateScopeCall();
|
||||
|
||||
if (SecurityTokenProvider.instance.get()!=null)
|
||||
validatePolicy(SecurityTokenProvider.instance.get(), call);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResponse(ResponseEvent e){
|
||||
SecurityTokenProvider.instance.reset();
|
||||
AuthorizationProvider.instance.reset();
|
||||
ScopeProvider.instance.reset();
|
||||
log.debug("resetting all the Thread local for this call.");
|
||||
}
|
||||
|
||||
|
||||
private void validateAgainstLifecycle(RequestEvent call) {
|
||||
|
||||
switch(context.lifecycle().state()) {
|
||||
|
@ -95,8 +80,10 @@ public class RequestValidator extends RequestHandler {
|
|||
|
||||
}
|
||||
|
||||
private void validateScope(String scope) {
|
||||
|
||||
private void validateScopeCall() {
|
||||
|
||||
String scope = ScopeProvider.instance.get();
|
||||
|
||||
if (scope == null) {
|
||||
log.warn("rejecting unscoped call to {}",context.name());
|
||||
invalid_request_error.fire("call is unscoped");
|
||||
|
@ -110,41 +97,18 @@ public class RequestValidator extends RequestHandler {
|
|||
log.warn("rejecting call to {} in invalid context {}, allowed context are {}",context.name(),scope,context.container().configuration().allowedContexts());
|
||||
invalid_request_error.fire(context.name()+" cannot be called in scope "+scope);
|
||||
}
|
||||
|
||||
ScopeProvider.instance.set(scope);
|
||||
}
|
||||
|
||||
private boolean validateToken(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 && scope==null && oauthCompatibility)
|
||||
token = call.request().getParameter(oauth_secret);
|
||||
private void rejectUnauthorizedCalls(RequestEvent call){
|
||||
|
||||
String token = SecurityTokenProvider.instance.get();
|
||||
String scope = ScopeProvider.instance.get();
|
||||
|
||||
if (token == null && scope==null){
|
||||
log.warn("rejecting call to {}, authorization required",context.name(),token);
|
||||
if (call.context().container().configuration().authenticationEnpoint()==null){
|
||||
if (call.request().getHeader(Constants.authorization_header)!=null){
|
||||
String basicAuthorization = call.request().getHeader(Constants.authorization_header);
|
||||
String base64Credentials = basicAuthorization.substring("Basic".length()).trim();
|
||||
String credentials = new String(DatatypeConverter.parseBase64Binary(base64Credentials));
|
||||
// credentials = username:password
|
||||
final String[] values = credentials.split(":",2);
|
||||
token = values[1];
|
||||
ClientInfo info = retreiveAndSetInfo(token, call);
|
||||
if (!(info instanceof UserInfo) || !info.getId().equals(values[0])) {
|
||||
log.warn("rejecting call to {}, username {} not valid for token {}",context.name(),values[0],token);
|
||||
RequestError.request_not_authorized_error.fire(context.name()+": username "+values[0]+" not valid for token "+token);
|
||||
}
|
||||
return true;
|
||||
}else {
|
||||
log.warn("rejecting call to {}, authorization required",context.name(),token);
|
||||
RequestError.request_not_authorized_error.fire(context.name()+": authorization required");
|
||||
}
|
||||
}else {
|
||||
log.info("authorization enpoint found on configuration, redirecting the call");
|
||||
String recallLocation = String.format("http://%s:%d%s", call.context().container().configuration().hostname(), call.context().container().configuration().port(), call.uri());
|
||||
|
@ -154,19 +118,9 @@ public class RequestValidator extends RequestHandler {
|
|||
} catch (IOException e) {
|
||||
log.error("errror redirecting call",e );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.trace("token is "+token);
|
||||
|
||||
if (token!=null){
|
||||
retreiveAndSetInfo(token, call);
|
||||
return true;
|
||||
}
|
||||
log.info("invalid token, checking the context");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -174,8 +128,8 @@ public class RequestValidator extends RequestHandler {
|
|||
return getName();
|
||||
}
|
||||
|
||||
private ClientInfo retreiveAndSetInfo(String token, RequestEvent call){
|
||||
log.info("accessing validator with token {} ", token);
|
||||
private void validatePolicy(String token, RequestEvent call){
|
||||
log.info("accessing policy validator with token {} ", token);
|
||||
AuthorizationEntry authEntry = null;
|
||||
try{
|
||||
authEntry = authorizationService().get(token);
|
||||
|
@ -195,11 +149,6 @@ public class RequestValidator extends RequestHandler {
|
|||
invalid_request_error.fire("rejecting call to "+context.name()+": "+authEntry.getClientInfo().getId()+" is not allowed to contact the service");
|
||||
}
|
||||
|
||||
AuthorizationProvider.instance.set(new Caller(authEntry.getClientInfo(), authEntry.getQualifier()));
|
||||
validateScope(authEntry.getContext());
|
||||
log.info("retrieved request authorization info {} in scope {} ", AuthorizationProvider.instance.get(), authEntry.getContext());
|
||||
SecurityTokenProvider.instance.set(token);
|
||||
return authEntry.getClientInfo();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package org.gcube.smartgears.utils;
|
||||
|
||||
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class InnerMethodName {
|
||||
|
||||
public static InnerMethodName instance = new InnerMethodName();
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(CalledMethodProvider.class);
|
||||
|
||||
// Thread local variable containing each thread's ID
|
||||
private static final InheritableThreadLocal<String> threadMethod =
|
||||
new InheritableThreadLocal<String>() {
|
||||
|
||||
@Override protected String initialValue() {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private InnerMethodName(){}
|
||||
|
||||
public String get(){
|
||||
String calledMethod = threadMethod.get();
|
||||
logger.trace("getting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
||||
return calledMethod;
|
||||
}
|
||||
|
||||
public void set(String calledMethod){
|
||||
if (calledMethod==null) return;
|
||||
threadMethod.set(calledMethod);
|
||||
logger.trace("setting InnerMethodName as "+calledMethod+" in thread "+Thread.currentThread().getId() );
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
threadMethod.remove();
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
<profile-management />
|
||||
</lifecycle>
|
||||
<request>
|
||||
<context-retriever />
|
||||
<request-validation />
|
||||
<request-accounting />
|
||||
</request>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
org.gcube.smartgears.handlers.application.lifecycle.ProfileManager
|
||||
org.gcube.smartgears.handlers.application.request.RequestValidator
|
||||
org.gcube.smartgears.handlers.application.request.RequestAccounting
|
||||
org.gcube.smartgears.handlers.application.request.RequestAccounting
|
||||
org.gcube.smartgears.handlers.application.request.RequestContextRetriever
|
Loading…
Reference in New Issue