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:
parent
49ba67fc4e
commit
9afd5b3834
|
@ -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>
|
|
@ -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
15
pom.xml
|
@ -2,7 +2,7 @@
|
|||
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>
|
||||
<groupId>org.gcube.common</groupId>
|
||||
<artifactId>authorization-library</artifactId>
|
||||
<artifactId>common-authorization</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>authorization service common library</name>
|
||||
|
||||
|
@ -16,6 +16,19 @@
|
|||
<distroDirectory>distro</distroDirectory>
|
||||
</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>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gcube.common.authorization.library;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
@ -9,15 +11,15 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
public class AuthorizationEntry {
|
||||
|
||||
private String userName;
|
||||
private String role;
|
||||
private List<String> roles;
|
||||
private String scope;
|
||||
|
||||
protected AuthorizationEntry(){}
|
||||
|
||||
public AuthorizationEntry(String userName, String role, String scope) {
|
||||
public AuthorizationEntry(String userName, List<String> roles, String scope) {
|
||||
super();
|
||||
this.userName = userName;
|
||||
this.role = role;
|
||||
this.roles = roles;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
|
@ -25,8 +27,8 @@ public class AuthorizationEntry {
|
|||
return userName;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
public List<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
|
@ -35,7 +37,7 @@ public class AuthorizationEntry {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthorizationEntry [userName=" + userName + ", role=" + role
|
||||
return "AuthorizationEntry [userName=" + userName + ", roles=" + roles
|
||||
+ ", scope=" + scope + "]";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -1,12 +1,18 @@
|
|||
package org.gcube.common.authorization.library.provider;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class AuthorizationProvider {
|
||||
|
||||
public static AuthorizationProvider instance = new AuthorizationProvider();
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(AuthorizationProvider.class);
|
||||
|
||||
// Thread local variable containing each thread's ID
|
||||
private static final ThreadLocal<UserInfo> threadAuth =
|
||||
new ThreadLocal<UserInfo>() {
|
||||
private static final InheritableThreadLocal<UserInfo> threadAuth =
|
||||
new InheritableThreadLocal<UserInfo>() {
|
||||
|
||||
@Override protected UserInfo initialValue() {
|
||||
return null;
|
||||
|
@ -17,11 +23,18 @@ public class AuthorizationProvider {
|
|||
private AuthorizationProvider(){}
|
||||
|
||||
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){
|
||||
threadAuth.set(authorizationToken);
|
||||
logger.info("setting "+authorizationToken+" in thread "+Thread.currentThread().getId() );
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
threadAuth.remove();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package org.gcube.common.authorization.library.provider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
@ -10,30 +12,34 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
public class UserInfo {
|
||||
|
||||
private String userName;
|
||||
private String role;
|
||||
private List<String> roles;
|
||||
private List<Service> bannedServices;
|
||||
|
||||
protected UserInfo(){}
|
||||
|
||||
public UserInfo(String userName, String role) {
|
||||
public UserInfo(String userName, List<String> roles, List<Service> bannedServices) {
|
||||
super();
|
||||
this.userName = userName;
|
||||
this.role = role;
|
||||
this.roles = roles;
|
||||
this.bannedServices = bannedServices;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
public String getRole() {
|
||||
return role;
|
||||
public List<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
||||
public List<Service> getBannedServices() {
|
||||
return bannedServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((role == null) ? 0 : role.hashCode());
|
||||
result = prime * result + ((roles == null) ? 0 : roles.hashCode());
|
||||
result = prime * result
|
||||
+ ((userName == null) ? 0 : userName.hashCode());
|
||||
return result;
|
||||
|
@ -48,10 +54,10 @@ public class UserInfo {
|
|||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
UserInfo other = (UserInfo) obj;
|
||||
if (role == null) {
|
||||
if (other.role != null)
|
||||
if (roles == null) {
|
||||
if (other.roles != null)
|
||||
return false;
|
||||
} else if (!role.equals(other.role))
|
||||
} else if (!roles.equals(other.roles))
|
||||
return false;
|
||||
if (userName == null) {
|
||||
if (other.userName != null)
|
||||
|
@ -63,7 +69,7 @@ public class UserInfo {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserInfo [userName=" + userName + ", role=" + role + "]";
|
||||
return "UserInfo [userName=" + userName + ", roles=" + roles + "]";
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue