diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java index e3ac6ef112f12704f6b09dfa92bab9cdd82d1a89..784f9ffb238bcc2a8ec85333b1d622f2e123c20f 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationDataProvider.java @@ -1,5 +1,6 @@ package ch.systemsx.cisd.openbis.generic.server.authorization; +import java.sql.Connection; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -478,4 +479,10 @@ final public class AuthorizationDataProvider implements IAuthorizationDataProvid { return list; } + + @Override + public Connection getConnection() + { + return daoFactory.getConnection(); + } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java index 6e82eefebdf9ab9dda55e889e3e26bde3a595ba4..398a3e9e0a3bff0743ec6687cbeca35c45347cad 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractBusinessObject.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo; +import java.sql.Connection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -442,4 +443,11 @@ abstract class AbstractBusinessObject implements IDAOFactory { return daoFactory.getExternalDataManagementSystemDAO(); } + + @Override + public Connection getConnection() + { + return daoFactory.getConnection(); + } + } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java index 1cc915c0e30558f089dc47e1013e1278a8970f7a..49d1c3648ec90d2bb2145b740e8308d14de1e8e3 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IAuthorizationDAOFactory.java @@ -16,6 +16,8 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess; +import java.sql.Connection; + import org.hibernate.SessionFactory; import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE; @@ -74,4 +76,9 @@ public interface IAuthorizationDAOFactory public IRelationshipTypeDAO getRelationshipTypeDAO(); public IDeletionDAO getDeletionDAO(); + + /** + * Returns the JDBC connection. + */ + public Connection getConnection(); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java index 2b5e07946ac1d87a4ce10682d3dec43517935862..f3418946584f568293fd99e2ce5740013ff53b4b 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AuthorizationDAOFactory.java @@ -16,6 +16,8 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db; +import java.sql.Connection; + import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.hibernate.SessionFactory; @@ -280,4 +282,12 @@ public class AuthorizationDAOFactory implements IAuthorizationDAOFactory HibernateUtils.setBatchUpdateMode(currentSession, batchMode); } + @SuppressWarnings("deprecation") + @Override + public Connection getConnection() + { + final SessionFactory sessionFactory = persistencyResources.getSessionFactoryOrNull(); + return sessionFactory.getCurrentSession().connection(); + } + } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java index 405d82b12370e58288f5cf6c4b5aa95e26638691..5276e843d7842913b232e0cabeb336c1632d223d 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.openbis.generic.shared.authorization; +import java.sql.Connection; import java.util.List; import java.util.Set; @@ -148,4 +149,9 @@ public interface IAuthorizationDataProvider extends IDatabaseInstanceFinder * Fetches all deletions with given tech ids. */ public List<DeletionPE> getDeletions(List<TechId> deletionIds); + + /** + * Returns the JDBC connection. + */ + public Connection getConnection(); } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java index 0781299114560cdb4ccc163207092899e095f6c4..947924f1cf239f669127856c4b87d6aff6929bc1 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/AbstractSpacePredicate.java @@ -76,7 +76,7 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance return Status.OK; } else { - return createError(person, spaceCodeOrNull); + return createError(person); } } @@ -85,13 +85,44 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance { return Status.OK; } - return createError(person, spaceCodeOrNull); + return createError(person); } - private Status createError(final PersonPE person, final String spaceCodeOrNull) + protected Status evaluate(final PersonPE person, final List<RoleWithIdentifier> allowedRoles, + final DatabaseInstancePE databaseInstance, final long spaceTechId) + { + final String databaseInstanceUUID = databaseInstance.getUuid(); + return evaluate(person, allowedRoles, databaseInstanceUUID, databaseInstance.getCode(), + spaceTechId); + } + + protected Status evaluate(final PersonPE person, final List<RoleWithIdentifier> allowedRoles, + final String databaseInstanceUUID, final String databaseInstanceCode, + final long spaceTechId) + { + if (tryFindSpace(databaseInstanceUUID, spaceTechId) == null) + { + if (okForNonExistentSpaces) + { + return Status.OK; + } else + { + return createError(person); + } + } + + final boolean matching = isMatching(allowedRoles, databaseInstanceUUID, spaceTechId); + if (matching) + { + return Status.OK; + } + return createError(person); + } + + private Status createError(final PersonPE person) { return Status.createError(String.format("User '%s' does not have enough privileges.", - person.getUserId(), spaceCodeOrNull)); + person.getUserId())); } private SpacePE tryFindSpace(final String databaseInstanceUUID, final String spaceCode) @@ -106,6 +137,18 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance return null; } + private SpacePE tryFindSpace(final String databaseInstanceUUID, final long spaceTechId) + { + for (final SpacePE space : spaces) + { + if (equalIdentifier(space, databaseInstanceUUID, spaceTechId)) + { + return space; + } + } + return null; + } + private boolean isMatching(final List<RoleWithIdentifier> allowedRoles, final String databaseInstanceUUID, final String spaceCodeOrNull) { @@ -128,6 +171,28 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance return false; } + private boolean isMatching(final List<RoleWithIdentifier> allowedRoles, + final String databaseInstanceUUID, final long spaceTechId) + { + for (final RoleWithIdentifier role : allowedRoles) + { + final RoleLevel roleLevel = role.getRoleLevel(); + if (roleLevel.equals(RoleLevel.SPACE) + && equalIdentifier(role.getAssignedSpace(), databaseInstanceUUID, + spaceTechId)) + { + return true; + } else if (roleLevel.equals(RoleLevel.INSTANCE) + && role.getAssignedDatabaseInstance().getUuid().equals(databaseInstanceUUID)) + { + // permissions on the database instance level allow to access all spaces in this + // instance + return true; + } + } + return false; + } + private boolean equalIdentifier(final SpacePE space, final String databaseInstanceUUID, final String spaceCodeOrNull) { @@ -135,14 +200,22 @@ public abstract class AbstractSpacePredicate<T> extends AbstractDatabaseInstance && space.getDatabaseInstance().getUuid().equals(databaseInstanceUUID); } - protected Status evaluateSpace(final PersonPE person, final List<RoleWithIdentifier> allowedRoles, final SpacePE spaceOrNull) + private boolean equalIdentifier(final SpacePE space, final String databaseInstanceUUID, + final long spaceTechId) + { + return (space.getId() == spaceTechId) + && space.getDatabaseInstance().getUuid().equals(databaseInstanceUUID); + } + + protected Status evaluateSpace(final PersonPE person, + final List<RoleWithIdentifier> allowedRoles, final SpacePE spaceOrNull) { if (spaceOrNull == null) { return Status.createError(String.format("User '%s' does not have enough privileges.", person.getUserId())); } - + final String spaceCode = SpaceCodeHelper.getSpaceCode(person, spaceOrNull); final DatabaseInstancePE databaseInstance = spaceOrNull.getDatabaseInstance(); return evaluate(person, allowedRoles, databaseInstance, spaceCode); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java index d705b54cc97f509b7cf76385c7605de3677904d6..bd25d5432b538da29960d0e8b824a92f26a2b0b4 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/internal/authorization/ScreeningPlateListReadOnlyPredicate.java @@ -16,15 +16,22 @@ package ch.systemsx.cisd.openbis.plugin.screening.shared.api.internal.authorization; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; + +import net.lemnik.eodsql.BaseQuery; +import net.lemnik.eodsql.QueryTool; +import net.lemnik.eodsql.Select; import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.StringArrayMapper; import ch.systemsx.cisd.openbis.generic.shared.authorization.RoleWithIdentifier; import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ShouldFlattenCollections; import ch.systemsx.cisd.openbis.generic.shared.authorization.predicate.AbstractSpacePredicate; -import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE; import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; import ch.systemsx.cisd.openbis.generic.shared.util.SpaceCodeHelper; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; @@ -52,27 +59,16 @@ public class ScreeningPlateListReadOnlyPredicate extends protected Status doEvaluation(PersonPE person, List<RoleWithIdentifier> allowedRoles, List<? extends PlateIdentifier> plates) { + final List<String> permIds = new ArrayList<String>(plates.size()); for (PlateIdentifier plate : plates) { if (plate.getPermId() != null) { - final SamplePE sampleOrNull = - authorizationDataProvider.tryGetSampleByPermId(plate.getPermId()); - if (sampleOrNull == null) - { - return Status.createError(String.format( - "User '%s' does not have enough privileges.", person.getUserId())); - } - final SpacePE space = sampleOrNull.getSpace(); - final Status status = - evaluate(person, allowedRoles, space.getDatabaseInstance(), space.getCode()); - if (Status.OK.equals(status) == false) - { - return status; - } + permIds.add(plate.getPermId()); } else { - final String spaceCode = SpaceCodeHelper.getSpaceCode(person, plate.tryGetSpaceCode()); + final String spaceCode = + SpaceCodeHelper.getSpaceCode(person, plate.tryGetSpaceCode()); if (plate.isSharedPlate() == false) { final Status status = @@ -85,7 +81,52 @@ public class ScreeningPlateListReadOnlyPredicate extends } } } + if (permIds.isEmpty() == false) + { + for (Long spaceId : getSampleSpaceIds(permIds)) + { + final Status status = + evaluate(person, allowedRoles, authorizationDataProvider + .getHomeDatabaseInstance(), spaceId); + if (Status.OK.equals(status) == false) + { + return status; + } + } + } return Status.OK; } + private final static int SAMPLE_PERM_ID_LIMIT = 999; + + interface ISampleToSpaceQuery extends BaseQuery + { + @Select(sql = "select distinct space_id from samples where perm_id = any(?{1})", parameterBindings = + { StringArrayMapper.class }) + public List<Long> getSampleSpaceIds(String[] samplePermIds); + } + + private Collection<Long> getSampleSpaceIds(final List<String> permIds) + { + final ISampleToSpaceQuery query = + QueryTool.getQuery(authorizationDataProvider.getConnection(), + ISampleToSpaceQuery.class); + if (permIds.size() > SAMPLE_PERM_ID_LIMIT) + { + final Set<Long> spaceIds = new HashSet<Long>(permIds.size()); + for (int startIdx = 0; startIdx < permIds.size(); startIdx += SAMPLE_PERM_ID_LIMIT) + { + final List<String> permIdSubList = permIds.subList(startIdx, + Math.min(permIds.size(), startIdx + SAMPLE_PERM_ID_LIMIT)); + spaceIds.addAll(query.getSampleSpaceIds(permIdSubList.toArray( + new String[permIdSubList.size()]))); + } + return spaceIds; + } else + { + return query + .getSampleSpaceIds(permIds.toArray(new String[permIds.size()])); + } + } + }