From 5fac16ec7bfaabbaa58a341fb638ddabb2d48d02 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Thu, 7 Apr 2011 07:10:25 +0000
Subject: [PATCH] LMS-2156 done

SVN: 20694
---
 .../server/DatasetSessionAuthorizer.java      | 20 ++++++
 .../DssServiceRpcAuthorizationAdvisor.java    | 69 +++++++++++--------
 .../server/EncapsulatedOpenBISService.java    |  5 ++
 .../shared/IEncapsulatedOpenBISService.java   |  6 ++
 .../authorization/DataSetAccessGuard.java     |  4 +-
 .../DssSessionAuthorizationHolder.java        |  5 ++
 .../authorization/IDssSessionAuthorizer.java  |  8 +++
 .../authorization/PrivilegeLevel.java         | 27 ++++++++
 .../openbis/generic/server/ETLService.java    |  6 ++
 .../generic/server/ETLServiceLogger.java      |  5 ++
 .../generic/shared/IETLLIMSService.java       |  7 ++
 .../shared/IETLLIMSService.java.expected      |  7 ++
 .../api/v1/IDssServiceRpcScreening.java       |  3 +-
 .../server/DssServiceRpcScreeningTest.java    | 14 ++--
 14 files changed, 147 insertions(+), 39 deletions(-)
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/PrivilegeLevel.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
index 738c9436897..421343d503f 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatasetSessionAuthorizer.java
@@ -178,6 +178,26 @@ public class DatasetSessionAuthorizer implements IDssSessionAuthorizer
         }
     }
 
+    public Status checkSpacePowerUserAuthorization(String sessionToken)
+    {
+        if (operationLog.isInfoEnabled())
+        {
+            operationLog.info(String.format(
+                    "Checking if session '%s' has space power user privileges on "
+                    + "openBIS application server.", sessionToken));
+        }
+        final IEncapsulatedOpenBISService openBISService = ServiceProvider.getOpenBISService();
+        
+        try
+        {
+            openBISService.checkSpacePowerUserAuthorization(sessionToken);
+            return Status.OK;
+        } catch (UserFailureException ex)
+        {
+            return Status.createError(ex.getMessage());
+        }
+    }
+    
     /**
      * Clears all entries from the cache (for unit tests).
      */
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcAuthorizationAdvisor.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcAuthorizationAdvisor.java
index 3f3de2f18d5..8705f2f9f5b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcAuthorizationAdvisor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DssServiceRpcAuthorizationAdvisor.java
@@ -42,6 +42,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.Da
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.DssSessionAuthorizationHolder;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.IAuthorizationGuardPredicate;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.IDssSessionAuthorizer;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.PrivilegeLevel;
 
 /**
  * The advisor for authorization in the DSS RPC interfaces.
@@ -213,15 +214,16 @@ public class DssServiceRpcAuthorizationAdvisor extends DefaultPointcutAdvisor
                     manager.lock(dataSetCode);
                 }
             }
-            boolean shouldLocksAutomaticallyBeReleased = shouldLocksAutomaticallyBeReleased(methodInvocation.getMethod());
+            boolean shouldLocksAutomaticallyBeReleased =
+                    shouldLocksAutomaticallyBeReleased(methodInvocation.getMethod());
             try
             {
-                final boolean requiresInstanceAdmin =
-                    checkRequiresInstanceAdmin(methodInvocation.getMethod(), sessionToken);
                 // At least one of the parameters must be annotated
-                assert requiresInstanceAdmin || annotatedParameters.size() > 0 : "No guard defined";
-                
-                if (requiresInstanceAdmin == false) // An instance admin is allowed to work on all data sets.
+                assert annotatedParameters.size() > 0 : "No guard defined";
+                PrivilegeLevel level = getAndCheckPrivilegeLevel(sessionToken, methodInvocation.getMethod());
+
+                if (level != PrivilegeLevel.INSTANCE_ADMIN) // An instance admin is allowed to work on all
+                                                    // data sets.
                 {
                     final Object recv = methodInvocation.getThis();
                     
@@ -266,38 +268,45 @@ public class DssServiceRpcAuthorizationAdvisor extends DefaultPointcutAdvisor
             DataSetAccessGuard guard = method.getAnnotation(DataSetAccessGuard.class);
             return guard == null ? true : guard.releaseDataSetLocks();
         }
-
-        private boolean checkRequiresInstanceAdmin(final Method method, final String sessionToken)
+        
+        private PrivilegeLevel getAndCheckPrivilegeLevel(String sessionToken, Method method)
         {
-            final DataSetAccessGuard guard = method.getAnnotation(DataSetAccessGuard.class);
-            final boolean requiresInstanceAdmin =
-                    (guard != null) ? guard.requiresInstanceAdmin() : false;
+            DataSetAccessGuard guard = method.getAnnotation(DataSetAccessGuard.class);
+            PrivilegeLevel level = guard == null ? PrivilegeLevel.DEFAULT : guard.privilegeLevel();
             if (operationLog.isInfoEnabled())
             {
-                operationLog.info("Check instance admin privileges.");
+                operationLog.info("Check access for privilege level " + level);
             }
-
-            if (requiresInstanceAdmin)
+            IDssSessionAuthorizer authorizer = DssSessionAuthorizationHolder.getAuthorizer();
+            Status status;
+            switch (level)
             {
-                final Status status =
-                        DssSessionAuthorizationHolder.getAuthorizer()
-                                .checkInstanceAdminAuthorization(sessionToken);
-                if (status != Status.OK)
+                case INSTANCE_ADMIN:
+                    status = authorizer.checkInstanceAdminAuthorization(sessionToken);
+                    break;
+                case SPACE_POWER_USER:
+                    status = authorizer.checkSpacePowerUserAuthorization(sessionToken);
+                    break;
+                default:
+                    status = Status.OK;
+                    break;
+            }
+            if (status.isError())
+            {
+                authorizationLog.info(String.format(
+                        "[SESSION:'%s']: Authorization failure while "
+                                + "invoking method '%s', user has not " + level + " privilege.",
+                        sessionToken, MethodUtils.describeMethod(method)));
+                String errorMessage = "You have not " + level + " privilege.";
+                if (null != status.tryGetErrorMessage())
                 {
-                    authorizationLog.info(String.format(
-                            "[SESSION:'%s']: Authorization failure while "
-                                    + "invoking method '%s', user is not an instance admin.",
-                            sessionToken, MethodUtils.describeMethod(method)));
-                    String errorMessage = "You are not an instance administrator.";
-                    if (null != status.tryGetErrorMessage())
-                    {
-                        errorMessage = status.tryGetErrorMessage();
-                    }
-
-                    throw new AuthorizationFailureException(errorMessage);
+                    errorMessage = status.tryGetErrorMessage();
                 }
+
+                throw new AuthorizationFailureException(errorMessage);
+                
             }
-            return requiresInstanceAdmin;
+            return level;
         }
 
         /**
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
index cc58bebb37f..ce3ec7336c4 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
@@ -398,6 +398,11 @@ public final class EncapsulatedOpenBISService implements IEncapsulatedOpenBISSer
         service.checkInstanceAdminAuthorization(sToken);
     }
 
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException
+    {
+        service.checkSpacePowerUserAuthorization(sessionToken);
+    }
+
     public void checkDataSetAccess(String sToken, String dataSetCode)
             throws UserFailureException
     {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
index 6a287a22ca4..e77b7431702 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
@@ -85,6 +85,12 @@ public interface IEncapsulatedOpenBISService
     @ManagedAuthentication
     public void checkInstanceAdminAuthorization(String sessionToken) throws UserFailureException;
 
+    /**
+     * Checks if the current user has SPACE_POWER_USER access rights.
+     */
+    @ManagedAuthentication
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException;
+    
     /**
      * Checks if the current user has access rights to a dataset with the specified data set code.
      */
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DataSetAccessGuard.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DataSetAccessGuard.java
index 4ab636eb4da..0acaaa3d0e5 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DataSetAccessGuard.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DataSetAccessGuard.java
@@ -36,9 +36,9 @@ import java.lang.annotation.Target;
 public @interface DataSetAccessGuard
 {
     /**
-     * If calling this method requires instance admin privileges.
+     * Privilege level.
      */
-    boolean requiresInstanceAdmin() default false;
+    PrivilegeLevel privilegeLevel() default PrivilegeLevel.DEFAULT;
     
     /**
      * By default locks on data sets are released after method invocation. 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
index 52669187b25..de0a967d1b9 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/DssSessionAuthorizationHolder.java
@@ -53,6 +53,11 @@ public class DssSessionAuthorizationHolder
             {
                 return Status.createError("Data set authorizer not set.");
             }
+
+            public Status checkSpacePowerUserAuthorization(String sessionToken)
+            {
+                return Status.createError("Data set authorizer not set.");
+            }
         };
 
     /**
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
index c5c5212dd30..35fdba6e44d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/IDssSessionAuthorizer.java
@@ -61,4 +61,12 @@ public interface IDssSessionAuthorizer
      * @return {@link Status#OK} if the access is granted, an error status otherwise. 
      */
     public Status checkInstanceAdminAuthorization(String sessionToken);
+
+    /**
+     * Checks whether the session identified by <var>sessionToken</var> has openBIS space power user
+     * privileges.
+     * 
+     * @return {@link Status#OK} if the access is granted, an error status otherwise.
+     */
+    public Status checkSpacePowerUserAuthorization(String sessionToken);
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/PrivilegeLevel.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/PrivilegeLevel.java
new file mode 100644
index 00000000000..bb235813581
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/api/internal/authorization/PrivilegeLevel.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization;
+
+/**
+ * Privilege level of data set access.
+ *
+ * @author Franz-Josef Elmer
+ */
+public enum PrivilegeLevel
+{
+    INSTANCE_ADMIN, SPACE_POWER_USER, DEFAULT;
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
index 4257a2a156a..b3c54130af7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
@@ -734,6 +734,12 @@ public class ETLService extends AbstractCommonServer<IETLService> implements IET
         // do nothing, the access rights specified in method annotations are checked by a proxy
     }
 
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException
+    {
+        checkSession(sessionToken);
+        // do nothing, the access rights specified in method annotations are checked by a proxy
+    }
+
     public void checkDataSetAccess(String sessionToken, String dataSetCode)
             throws UserFailureException
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceLogger.java
index 76a24ea4757..fcbcbb36ca8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceLogger.java
@@ -246,6 +246,11 @@ public class ETLServiceLogger extends AbstractServerLogger implements IETLServic
         logAccess(sessionToken, "checkInstanceAdminAuthorization");
     }
 
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException
+    {
+        logAccess(sessionToken, "checkSpacePowerUserAuthorization");
+    }
+
     public void checkDataSetAccess(String sessionToken, String dataSetCode)
             throws UserFailureException
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
index e0d33f4e8f5..1c8539c0c2d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java
@@ -348,6 +348,13 @@ public interface IETLLIMSService extends IServer, ISessionProvider
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
     public void checkInstanceAdminAuthorization(String sessionToken) throws UserFailureException;
+    
+    /**
+     * Checks that the user of specified session has SPACE_POWER_USER access rights.
+     */
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException;
 
     /**
      * Does nothing besides checking that the current user has rights to access the content of the
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java.expected b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java.expected
index e0d33f4e8f5..1c8539c0c2d 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java.expected
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/IETLLIMSService.java.expected
@@ -348,6 +348,13 @@ public interface IETLLIMSService extends IServer, ISessionProvider
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
     public void checkInstanceAdminAuthorization(String sessionToken) throws UserFailureException;
+    
+    /**
+     * Checks that the user of specified session has SPACE_POWER_USER access rights.
+     */
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleWithHierarchy.SPACE_POWER_USER)
+    public void checkSpacePowerUserAuthorization(String sessionToken) throws UserFailureException;
 
     /**
      * Does nothing besides checking that the current user has rights to access the content of the
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
index 1b49df19662..0bde2cd6a48 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/shared/api/v1/IDssServiceRpcScreening.java
@@ -24,6 +24,7 @@ import ch.systemsx.cisd.common.api.IRpcService;
 import ch.systemsx.cisd.common.api.MinimalMinorVersion;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.AuthorizationGuard;
 import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.DataSetAccessGuard;
+import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.authorization.PrivilegeLevel;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.internal.authorization.DatasetIdentifierPredicate;
 import ch.systemsx.cisd.openbis.dss.screening.shared.api.internal.authorization.SingleDataSetIdentifierPredicate;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDataset;
@@ -309,7 +310,7 @@ public interface IDssServiceRpcScreening extends IRpcService
      * @since 1.4
      */
     @MinimalMinorVersion(4)
-    @DataSetAccessGuard(requiresInstanceAdmin = true)
+    @DataSetAccessGuard(privilegeLevel = PrivilegeLevel.SPACE_POWER_USER)
     public void saveImageTransformerFactory(
             String sessionToken,
             @AuthorizationGuard(guardClass = DatasetIdentifierPredicate.class) List<IDatasetIdentifier> dataSetIdentifiers,
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
index a872a86b1be..7a603291db4 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreeningTest.java
@@ -439,8 +439,8 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
         context.checking(new Expectations()
             {
                 {
-                    one(service).checkInstanceAdminAuthorization(SESSION_TOKEN);
-                    will(throwException(new UserFailureException("You are not an admin.")));
+                    one(service).checkSpacePowerUserAuthorization(SESSION_TOKEN);
+                    will(throwException(new UserFailureException("You are not a space power user.")));
                 }
             });
 
@@ -451,7 +451,7 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
             fail("Unauthorized access not detected.");
         } catch (AuthorizationFailureException ex)
         {
-            assertEquals("Authorization failure: You are not an admin.", ex.getMessage());
+            assertEquals("Authorization failure: You are not a space power user.", ex.getMessage());
         }
 
         assertTrue(testMethodInterceptor.methodInvoked);
@@ -465,11 +465,12 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
         final DatasetIdentifier ds2 = new DatasetIdentifier("ds2", "url1");
         final String channel = "dapi";
         prepareLockDataSet(DATASET_CODE, "ds2");
+        prepareAssetDataSetsAreAccessible();
         context.checking(new Expectations()
             {
                 {
-                    one(service).checkInstanceAdminAuthorization(SESSION_TOKEN);
-
+                    one(service).checkSpacePowerUserAuthorization(SESSION_TOKEN);
+                    
                     long datasetId = 123;
                     ImgDatasetDTO dataset = createDataset(datasetId);
                     dataset.setPermId(DATASET_CODE);
@@ -509,10 +510,11 @@ public class DssServiceRpcScreeningTest extends AssertJUnit
     {
         final DatasetIdentifier ds1 = new DatasetIdentifier(DATASET_CODE, "url1");
         prepareLockDataSet(DATASET_CODE);
+        prepareAssetDataSetsAreAccessible("ds1");
         context.checking(new Expectations()
             {
                 {
-                    one(service).checkInstanceAdminAuthorization(SESSION_TOKEN);
+                    one(service).checkSpacePowerUserAuthorization(SESSION_TOKEN);
 
                     Long containerId = 312L;
 
-- 
GitLab