authorization-service/src/main/java/org/gcube/common/authorizationservice/persistence/RelationDBPersistence.java

409 lines
15 KiB
Java

package org.gcube.common.authorizationservice.persistence;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import lombok.extern.slf4j.Slf4j;
import org.gcube.common.authorization.library.AuthorizationEntry;
import org.gcube.common.authorization.library.ClientType;
import org.gcube.common.authorization.library.policies.Policy;
import org.gcube.common.authorization.library.policies.PolicyType;
import org.gcube.common.authorization.library.policies.Service2ServicePolicy;
import org.gcube.common.authorization.library.policies.User2ServicePolicy;
import org.gcube.common.authorization.library.provider.ClientInfo;
import org.gcube.common.authorization.library.provider.ContainerInfo;
import org.gcube.common.authorization.library.provider.ExternalServiceInfo;
import org.gcube.common.authorization.library.provider.ServiceIdentifier;
import org.gcube.common.authorization.library.provider.ServiceInfo;
import org.gcube.common.authorization.library.provider.UserInfo;
import org.gcube.common.authorizationservice.persistence.entities.AuthorizationEntity;
import org.gcube.common.authorizationservice.persistence.entities.AuthorizationId;
import org.gcube.common.authorizationservice.persistence.entities.EntityConstants;
import org.gcube.common.authorizationservice.persistence.entities.ExternalServiceAuthorizationEntity;
import org.gcube.common.authorizationservice.persistence.entities.NodeAuthorizationEntity;
import org.gcube.common.authorizationservice.persistence.entities.PolicyEntity;
import org.gcube.common.authorizationservice.persistence.entities.ServiceAuthorizationEntity;
import org.gcube.common.authorizationservice.persistence.entities.ServicePolicyEntity;
import org.gcube.common.authorizationservice.persistence.entities.UserAuthorizationEntity;
import org.gcube.common.authorizationservice.persistence.entities.UserPolicyEntity;
import org.gcube.common.authorizationservice.util.TokenPersistence;
@Singleton
@Slf4j
public class RelationDBPersistence implements TokenPersistence{
@Inject
EntityManagerFactory emFactory;
ReentrantLock lock = new ReentrantLock(true);
HashMap<String, AuthorizationId> synchMap = new HashMap<String, AuthorizationId>();
//ONLY FOR TEST PURPOSE
public void setEntitymanagerFactory(EntityManagerFactory emf){
this.emFactory = emf;
}
@Override
public AuthorizationEntry getAuthorizationEntry(String token) {
EntityManager em = emFactory.createEntityManager();
try{
//retrieve entity for token
TypedQuery<AuthorizationEntity> query = em.createNamedQuery("Authz.get", AuthorizationEntity.class);
query.setParameter("token", token);
AuthorizationEntity authEntity;
try{
authEntity = query.getSingleResult();
}catch (NoResultException e){
log.warn("no result found for token {}",token);
return null;
}
if (authEntity.getEntryType().equals(EntityConstants.SERVICE_AUTHORIZATION)){
ServiceAuthorizationEntity sAuth = (ServiceAuthorizationEntity) authEntity;
return new AuthorizationEntry(sAuth.getInfo(), sAuth.getContext(), retrievePolicies(sAuth, em), sAuth.getQualifier());
} else if (authEntity.getEntryType().equals(EntityConstants.USER_AUTHORIZATION)){
UserAuthorizationEntity uAuth = (UserAuthorizationEntity) authEntity;
return new AuthorizationEntry(uAuth.getInfo(), uAuth.getContext(), retrievePolicies(uAuth, em), uAuth.getQualifier());
} else if (authEntity.getEntryType().equals(EntityConstants.EXTERNAL_SERVICE_AUTHORIZATION)){
ExternalServiceAuthorizationEntity uAuth = (ExternalServiceAuthorizationEntity) authEntity;
return new AuthorizationEntry(uAuth.getInfo(), uAuth.getContext(), new ArrayList<Policy>(), uAuth.getQualifier());
} else if (authEntity.getEntryType().equals(EntityConstants.CONTAINER_AUTHORIZATION)){
NodeAuthorizationEntity uAuth = (NodeAuthorizationEntity) authEntity;
return new AuthorizationEntry(uAuth.getInfo(), uAuth.getContext(), new ArrayList<Policy>(), uAuth.getQualifier());
} else throw new IllegalArgumentException("entryType cannot be mapped");
}catch(Throwable t){
log.error("error retrieving authorization entry",t);
return null;
}finally{
em.close();
}
}
@Override
public String getExistingToken(String clientId, String context, String qualifier) {
EntityManager em = emFactory.createEntityManager();
try{
AuthorizationEntity authEntity = em.find(AuthorizationEntity.class, new AuthorizationId(context, clientId, qualifier));
if (authEntity!=null)
return authEntity.getToken();
return null;
}finally{
em.close();
}
}
@Override
public void saveAuthorizationEntry(String token, String context,
ClientInfo info, String tokenQualifier, String generatedBy) {
AuthorizationEntity authEntity = null;
if (info instanceof UserInfo)
authEntity = new UserAuthorizationEntity(token, context, tokenQualifier, (UserInfo) info);
else if (info instanceof ServiceInfo) authEntity = new ServiceAuthorizationEntity(token, context, tokenQualifier, (ServiceInfo) info, generatedBy);
else if (info instanceof ExternalServiceInfo) authEntity = new ExternalServiceAuthorizationEntity(token, context, tokenQualifier, (ExternalServiceInfo) info, generatedBy);
else authEntity = new NodeAuthorizationEntity(token, context, tokenQualifier, (ContainerInfo) info, generatedBy);
AuthorizationId authId = new AuthorizationId(context, info.getId(), tokenQualifier);
lock.lock();
try{
if (synchMap.containsKey(authId.toString()))
authId = synchMap.get(authId.toString());
else synchMap.put(authId.toString(), authId);
}finally{
lock.unlock();
}
synchronized (authId) {
EntityManager em = emFactory.createEntityManager();
EntityTransaction tx = em.getTransaction();
try{
tx.begin();
AuthorizationEntity ae = em.find(AuthorizationEntity.class, authId);
log.trace("AuthorizationEntity {} found, saving it", (ae==null)?"not":"");
if (ae==null)
em.persist(authEntity);
tx.commit();
}catch(RuntimeException e){
log.error("error saving authorization Entry", e);
if (tx.isActive())
tx.rollback();
throw e;
} finally{
em.close();
synchMap.remove(authId.toString());
}
}
}
@Override
public void updateAuthorizationEntry(String token,
List<String> roles) {
EntityManager em = emFactory.createEntityManager();
TypedQuery<AuthorizationEntity> query = em.createNamedQuery("Authz.get", AuthorizationEntity.class);
query.setParameter("token", token);
AuthorizationEntity authEntity;
try{
authEntity = query.getSingleResult();
}catch (NoResultException e){
log.warn("no result found for token {}",token);
throw new IllegalArgumentException("the token does not exist");
}
if (authEntity.getInfo().getType()== ClientType.USER) {
log.debug("setting roles {}", roles);
UserInfo ui = new UserInfo(authEntity.getInfo().getId(), roles);
authEntity.setInfo(ui);
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
AuthorizationEntity merged = em.merge(authEntity);
tx.commit();
log.debug("entity merged: {}", merged);
}finally {
em.close();
}
} else
throw new IllegalArgumentException("the token is not representing a user");
}
@Override
public void addPolicies(List<Policy> polices) {
EntityManager em = emFactory.createEntityManager();
try{
em.getTransaction().begin();
for (Policy policy: polices)
if (policy.getPolicyType()==PolicyType.SERVICE){
Service2ServicePolicy s2sPolicy = (Service2ServicePolicy) policy;
em.persist(new ServicePolicyEntity(s2sPolicy.getContext(), s2sPolicy.getServiceAccess(), s2sPolicy.getClient(), s2sPolicy.getMode()));
} else {
User2ServicePolicy u2sPolicy = (User2ServicePolicy) policy;
em.persist(new UserPolicyEntity(u2sPolicy.getContext(), u2sPolicy.getServiceAccess(), u2sPolicy.getEntity(), u2sPolicy.getMode()));
}
em.getTransaction().commit();
}catch (Exception e) {
log.error("error storing policy",e);
throw new RuntimeException(e);
}finally{
em.close();
}
}
@Override
public void removePolicy(long policyId) {
EntityManager em = emFactory.createEntityManager();
try{
em.getTransaction().begin();
PolicyEntity entity = em.find(PolicyEntity.class, policyId);
if (entity!= null){
em.remove(entity);
//TODO: throw an exception
}
else log.warn("policy with id {} not found", policyId);
em.getTransaction().commit();
}catch (Exception e) {
log.error("error removing policy with id {}", policyId,e);
throw new RuntimeException(e);
}finally{
em.close();
}
}
@Override
public List<Policy> getPolices(String context) {
List<Policy> policiesToReturn = new ArrayList<Policy>();
EntityManager em = emFactory.createEntityManager();
try{
TypedQuery<PolicyEntity> query = em.createNamedQuery("Policy.allPolicies", PolicyEntity.class);
query.setParameter("context", context);
log.info("query to get all policies in context {} , {} ", query.getParameterValue("context"), query.toString());
List<PolicyEntity> entities = query.getResultList();
for (PolicyEntity pEntity: entities ){
Policy policy;
if (pEntity.getPolicyType().equals(EntityConstants.SERVICE_POLICY)){
policy = new Service2ServicePolicy(pEntity.getContext(), pEntity.getServiceAccess(), ((ServicePolicyEntity) pEntity).getClientAccess(), pEntity.getAction());
}else
policy = new User2ServicePolicy(pEntity.getContext(), pEntity.getServiceAccess(), ((UserPolicyEntity) pEntity).getUser(), pEntity.getAction());
policy.setId(pEntity.getId());
policy.setCreationTime(pEntity.getCreationTime());
policy.setLastUpdateTime(pEntity.getLastUpdateTime());
policiesToReturn.add(policy);
}
}finally{
em.close();
}
log.info("policies to return are {} ",policiesToReturn.size());
return policiesToReturn;
}
@Override
public List<Policy> getPolicesByType(String context, PolicyType type) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Policy> getPolicesByTypeAndClientId(String context, PolicyType type, String clientId) {
// TODO Auto-generated method stub
return null;
}
private List<Policy> retrievePolicies(UserAuthorizationEntity uAuth, EntityManager em){
List<Policy> policies = new ArrayList<Policy>();
TypedQuery<UserPolicyEntity> queryU = em.createNamedQuery("UserPolicy.get", UserPolicyEntity.class);
queryU.setParameter("context", uAuth.getContext());
queryU.setParameter("user", uAuth.getInfo().getId());
if (!uAuth.getInfo().getRoles().isEmpty())
queryU.setParameter("rolesList", uAuth.getInfo().getRoles());
else queryU.setParameter("rolesList", Collections.singleton(""));
List<UserPolicyEntity> userPolicies = queryU.getResultList();
for (UserPolicyEntity uPolicy: userPolicies){
User2ServicePolicy u2sP = new User2ServicePolicy(uPolicy.getContext(), uPolicy.getServiceAccess(), uPolicy.getUser(), uPolicy.getAction());
u2sP.setCreationTime(uPolicy.getCreationTime());
u2sP.setLastUpdateTime(uPolicy.getLastUpdateTime());
policies.add(u2sP);
}
log.debug("user policies found are {}", policies);
return policies;
}
private List<Policy> retrievePolicies(ServiceAuthorizationEntity sAuth, EntityManager em){
List<Policy> policies = new ArrayList<Policy>();
ServiceIdentifier sIdentifier = ((ServiceInfo)sAuth.getInfo()).getServiceIdentifier();
TypedQuery<ServicePolicyEntity> queryS = em.createNamedQuery("ServicePolicy.get", ServicePolicyEntity.class);
queryS.setParameter("context", sAuth.getContext());
queryS.setParameter("serviceClass", sIdentifier.getServiceClass());
queryS.setParameter("serviceName", sIdentifier.getServiceName());
queryS.setParameter("identifier", sIdentifier.getServiceId());
List<ServicePolicyEntity> servicePolicies = queryS.getResultList();
for (ServicePolicyEntity sPolicy: servicePolicies){
Service2ServicePolicy s2sP = new Service2ServicePolicy(sPolicy.getContext(), sPolicy.getServiceAccess(), sPolicy.getClientAccess(), sPolicy.getAction());
s2sP.setCreationTime(sPolicy.getCreationTime());
s2sP.setLastUpdateTime(sPolicy.getLastUpdateTime());
policies.add(s2sP);
}
log.debug("service policies found are {}", policies);
return policies;
}
/**
*
*
* return a map with key qualifier and value the corresponding token
*/
@Override
public Map<String, String> getExistingApiKeys(String clientId, String context) {
EntityManager em = emFactory.createEntityManager();
try{
TypedQuery<AuthorizationEntity> queryS = em.createNamedQuery("Authz.getQualifiers", AuthorizationEntity.class);
queryS.setParameter("context", context);
queryS.setParameter("clientId", clientId);
List<AuthorizationEntity> apikeys = queryS.getResultList();
Map<String, String> qualifiers = new HashMap<String, String>();
for (AuthorizationEntity apikey: apikeys)
qualifiers.put(apikey.getQualifier(), apikey.getToken());
return qualifiers;
}finally{
em.close();
}
}
/**
*
*
* return a map with key the external service id and value the corresponding token
*/
@Override
public Map<String, String> getExistingExternalServices(String generatorId, String context) {
EntityManager em = emFactory.createEntityManager();
try{
TypedQuery<ExternalServiceAuthorizationEntity> queryS = em.createNamedQuery("ExternalService.getByGenerator", ExternalServiceAuthorizationEntity.class);
queryS.setParameter("context", context);
queryS.setParameter("generatorId", generatorId);
List<ExternalServiceAuthorizationEntity> externals = queryS.getResultList();
Map<String, String> externalServiceMapping = new HashMap<String, String>();
for (ExternalServiceAuthorizationEntity external: externals)
externalServiceMapping.put(external.getClientId(), external.getToken());
return externalServiceMapping;
}finally{
em.close();
}
}
@Override
public void removeApiKey(String token) {
EntityManager em = emFactory.createEntityManager();
try{
em.getTransaction().begin();
TypedQuery<AuthorizationEntity> queryS = em.createNamedQuery("Authz.getByToken", AuthorizationEntity.class);
queryS.setParameter("token", token);
AuthorizationEntity authEntry = queryS.getSingleResult();
if (authEntry != null)
em.remove(authEntry);
em.getTransaction().commit();
}catch (Exception e) {
log.error("error removing apikey {}", token);
em.close();
}
}
@Override
public void removeAllAuthorizationsEntryForClientId(String context, String clientId) {
EntityManager em = emFactory.createEntityManager();
try{
em.getTransaction().begin();
TypedQuery<AuthorizationEntity> queryS = em.createNamedQuery("Authz.getGeneratedTokenByClientId", AuthorizationEntity.class);
queryS.setParameter("clientid", clientId);
queryS.setParameter("context", context);
List<AuthorizationEntity> authEntries = queryS.getResultList();
for (AuthorizationEntity entry:authEntries)
em.remove(entry);
em.getTransaction().commit();
}catch (Exception e) {
log.error("error removing client authorization for user {} ", clientId);
em.close();
}
}
}