70: Authetication Token

Task-Url: https://support.d4science.org/issues/70

git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/Common/authorization-common-library@115160 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Lucio Lelii 2015-05-29 16:32:49 +00:00
parent 49ba67fc4e
commit 9afd5b3834
13 changed files with 378 additions and 23 deletions

36
.classpath Normal file
View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>authorization-common-library</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

15
pom.xml
View File

@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.common</groupId> <groupId>org.gcube.common</groupId>
<artifactId>authorization-library</artifactId> <artifactId>common-authorization</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
<name>authorization service common library</name> <name>authorization service common library</name>
@ -16,6 +16,19 @@
<distroDirectory>distro</distroDirectory> <distroDirectory>distro</distroDirectory>
</properties> </properties>
<dependencies>
<dependency>
<groupId>org.gcube.core</groupId>
<artifactId>common-scope</artifactId>
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>

View File

@ -1,5 +1,7 @@
package org.gcube.common.authorization.library; package org.gcube.common.authorization.library;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
@ -9,15 +11,15 @@ import javax.xml.bind.annotation.XmlRootElement;
public class AuthorizationEntry { public class AuthorizationEntry {
private String userName; private String userName;
private String role; private List<String> roles;
private String scope; private String scope;
protected AuthorizationEntry(){} protected AuthorizationEntry(){}
public AuthorizationEntry(String userName, String role, String scope) { public AuthorizationEntry(String userName, List<String> roles, String scope) {
super(); super();
this.userName = userName; this.userName = userName;
this.role = role; this.roles = roles;
this.scope = scope; this.scope = scope;
} }
@ -25,8 +27,8 @@ public class AuthorizationEntry {
return userName; return userName;
} }
public String getRole() { public List<String> getRoles() {
return role; return roles;
} }
public String getScope() { public String getScope() {
@ -35,7 +37,7 @@ public class AuthorizationEntry {
@Override @Override
public String toString() { public String toString() {
return "AuthorizationEntry [userName=" + userName + ", role=" + role return "AuthorizationEntry [userName=" + userName + ", roles=" + roles
+ ", scope=" + scope + "]"; + ", scope=" + scope + "]";
} }

View File

@ -0,0 +1,62 @@
package org.gcube.common.authorization.library;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.gcube.common.authorization.library.annotations.IsAllowedFor;
import org.gcube.common.authorization.library.annotations.SubjectToQuota;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.Service;
import org.gcube.common.authorization.library.provider.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthorizationInvocationHandler<T, I extends T> implements InvocationHandler{
public static Logger log = LoggerFactory.getLogger(AuthorizationInvocationHandler.class);
private String handledClass;
private Object obj;
ResourceAuthorizationProxy<T, I> resourceAuthorizationProxy;
protected AuthorizationInvocationHandler(I obj, String className, ResourceAuthorizationProxy<T, I> resourceAuthorizationProxy) {
handledClass = className;
this.obj = obj;
this.resourceAuthorizationProxy = resourceAuthorizationProxy;
}
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
log.trace("calling proxed method "+method.getName()+" on "+handledClass);
UserInfo info = AuthorizationProvider.instance.get();
if(method.isAnnotationPresent(IsAllowedFor.class)){
IsAllowedFor allowed = method.getAnnotation(IsAllowedFor.class);
if (allowed.roles().length>0 && isOneElementContainedinRoles(info.getRoles(), allowed.roles())){
String message = "blocking method "+method.getName()+" for user "+info.getUserName()+": only roles "+Arrays.toString(allowed.roles()) +" can access";
log.warn(message);
throw new SecurityException(message);
}
}
if(method.isAnnotationPresent(SubjectToQuota.class)){
Service service = new Service(resourceAuthorizationProxy.getServiceClass(), resourceAuthorizationProxy.getServiceName());
if (info.getBannedServices().contains(service)){
String message = "blocking method "+method.getName()+" for user "+info.getUserName()+": overquota reached";
log.warn(message);
throw new SecurityException(message);
}
}
return method.invoke(obj, args);
}
private static boolean isOneElementContainedinRoles(List<String> elements, String[] allowedRoles){
for (String role: allowedRoles )
if (elements.contains(role))
return true;
return false;
}
}

View File

@ -0,0 +1,75 @@
package org.gcube.common.authorization.library;
import java.util.concurrent.Callable;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.UserInfo;
import org.gcube.common.scope.api.ScopeProvider;
public class AuthorizedTasks {
/**
* Binds a {@link Callable} task to the current scope and user.
* @param task the task
* @return an equivalent {@link Callable} task bound to the current scope and user
*/
static public <V> Callable<V> bind(final Callable<V> task) {
final String callScope = ScopeProvider.instance.get();
final UserInfo userCall = AuthorizationProvider.instance.get();
return new Callable<V>() {
@Override
public V call() throws Exception {
//bind underlying thread to callscope
ScopeProvider.instance.set(callScope);
//bind underlying thread to call user
AuthorizationProvider.instance.set(userCall);
try {
return task.call();
}
finally {
ScopeProvider.instance.reset();
AuthorizationProvider.instance.reset();
}
}
};
}
/**
* Binds a {@link Runnable} task to the current scope and user.
* @param task the task
* @return an equivalent {@link Runnable} task bound to the current scope and user
*/
static public <V> Runnable bind(final Runnable task) {
final String callScope = ScopeProvider.instance.get();
final UserInfo userCall = AuthorizationProvider.instance.get();
return new Runnable() {
@Override
public void run() {
//bind underlying thread to callscope
ScopeProvider.instance.set(callScope);
//bind underlying thread to call user
AuthorizationProvider.instance.set(userCall);
try {
task.run();
}
finally {
ScopeProvider.instance.reset();
AuthorizationProvider.instance.reset();
}
}
};
}
}

View File

@ -0,0 +1,16 @@
package org.gcube.common.authorization.library;
import java.lang.reflect.Proxy;
public class GenericProxyFactory {
@SuppressWarnings("unchecked")
public static <T, I extends T> T getProxy(Class<T> intf,
final I obj, ResourceAuthorizationProxy<T, I> resourceAuthorizationProxy) {
return (T)
Proxy.newProxyInstance(obj.getClass().getClassLoader(),
new Class[] { intf },
new AuthorizationInvocationHandler<T,I>(obj, intf.getSimpleName(), resourceAuthorizationProxy));
}
}

View File

@ -0,0 +1,19 @@
package org.gcube.common.authorization.library;
public abstract class ResourceAuthorizationProxy<I,T extends I> {
private I delegate;
public ResourceAuthorizationProxy(Class<I> classIntrface, T wrapped){
delegate = GenericProxyFactory.getProxy(classIntrface,wrapped, this );
}
public I getDelegate() {
return delegate;
}
public abstract String getServiceClass();
public abstract String getServiceName();
}

View File

@ -0,0 +1,15 @@
package org.gcube.common.authorization.library.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface IsAllowedFor {
String[] roles();
}

View File

@ -0,0 +1,14 @@
package org.gcube.common.authorization.library.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SubjectToQuota {
}

View File

@ -1,12 +1,18 @@
package org.gcube.common.authorization.library.provider; package org.gcube.common.authorization.library.provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AuthorizationProvider { public class AuthorizationProvider {
public static AuthorizationProvider instance = new AuthorizationProvider(); public static AuthorizationProvider instance = new AuthorizationProvider();
private static Logger logger = LoggerFactory.getLogger(AuthorizationProvider.class);
// Thread local variable containing each thread's ID // Thread local variable containing each thread's ID
private static final ThreadLocal<UserInfo> threadAuth = private static final InheritableThreadLocal<UserInfo> threadAuth =
new ThreadLocal<UserInfo>() { new InheritableThreadLocal<UserInfo>() {
@Override protected UserInfo initialValue() { @Override protected UserInfo initialValue() {
return null; return null;
@ -17,11 +23,18 @@ public class AuthorizationProvider {
private AuthorizationProvider(){} private AuthorizationProvider(){}
public UserInfo get(){ public UserInfo get(){
return threadAuth.get(); UserInfo info = threadAuth.get();
logger.info("getting "+info+" in thread "+Thread.currentThread().getId() );
return info;
} }
public void set(UserInfo authorizationToken){ public void set(UserInfo authorizationToken){
threadAuth.set(authorizationToken); threadAuth.set(authorizationToken);
logger.info("setting "+authorizationToken+" in thread "+Thread.currentThread().getId() );
}
public void reset(){
threadAuth.remove();
} }
} }

View File

@ -0,0 +1,61 @@
package org.gcube.common.authorization.library.provider;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Service {
private String serviceClass;
private String serviceName;
public Service(String serviceClass, String serviceName) {
super();
this.serviceClass = serviceClass;
this.serviceName = serviceName;
}
public String getServiceClass() {
return serviceClass;
}
public String getServiceName() {
return serviceName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((serviceClass == null) ? 0 : serviceClass.hashCode());
result = prime * result
+ ((serviceName == null) ? 0 : serviceName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Service other = (Service) obj;
if (serviceClass == null) {
if (other.serviceClass != null)
return false;
} else if (!serviceClass.equals(other.serviceClass))
return false;
if (serviceName == null) {
if (other.serviceName != null)
return false;
} else if (!serviceName.equals(other.serviceName))
return false;
return true;
}
}

View File

@ -1,5 +1,7 @@
package org.gcube.common.authorization.library.provider; package org.gcube.common.authorization.library.provider;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
@ -10,30 +12,34 @@ import javax.xml.bind.annotation.XmlRootElement;
public class UserInfo { public class UserInfo {
private String userName; private String userName;
private String role; private List<String> roles;
private List<Service> bannedServices;
protected UserInfo(){} protected UserInfo(){}
public UserInfo(String userName, String role) { public UserInfo(String userName, List<String> roles, List<Service> bannedServices) {
super(); super();
this.userName = userName; this.userName = userName;
this.role = role; this.roles = roles;
this.bannedServices = bannedServices;
} }
public String getUserName() { public String getUserName() {
return userName; return userName;
} }
public String getRole() { public List<String> getRoles() {
return role; return roles;
} }
public List<Service> getBannedServices() {
return bannedServices;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((role == null) ? 0 : role.hashCode()); result = prime * result + ((roles == null) ? 0 : roles.hashCode());
result = prime * result result = prime * result
+ ((userName == null) ? 0 : userName.hashCode()); + ((userName == null) ? 0 : userName.hashCode());
return result; return result;
@ -48,10 +54,10 @@ public class UserInfo {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
UserInfo other = (UserInfo) obj; UserInfo other = (UserInfo) obj;
if (role == null) { if (roles == null) {
if (other.role != null) if (other.roles != null)
return false; return false;
} else if (!role.equals(other.role)) } else if (!roles.equals(other.roles))
return false; return false;
if (userName == null) { if (userName == null) {
if (other.userName != null) if (other.userName != null)
@ -63,7 +69,7 @@ public class UserInfo {
@Override @Override
public String toString() { public String toString() {
return "UserInfo [userName=" + userName + ", role=" + role + "]"; return "UserInfo [userName=" + userName + ", roles=" + roles + "]";
} }