Skip to content

Commit

Permalink
feat: Add finer permission model for Transformation System
Browse files Browse the repository at this point in the history
Co-authored-by: Simon Fayer <sfayer@users.noreply.github.com>
Co-authored-by: fstagni <federico.stagni@cern.ch>
  • Loading branch information
3 people committed Aug 14, 2023
1 parent fa922bd commit 410937b
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ are showed in the next table:
+----------------------------+------------------------------------------------------------------+-------------+
| *PrivateLimitedDelegation* | Allow getting only limited proxies for one self | |
+----------------------------+------------------------------------------------------------------+-------------+
| *ProductionManagement* | Allow managing production | |
| *ProductionManagement* | Allow managing all productions | |
+----------------------------+------------------------------------------------------------------+-------------+
| *ProductionSharing* | Allow managing productions owned by the same group | |
+----------------------------+------------------------------------------------------------------+-------------+
| *ProductionUser* | Allow managing productions owned by the same user | |
+----------------------------+------------------------------------------------------------------+-------------+
| *ProxyManagement* | Allow managing proxies | |
+----------------------------+------------------------------------------------------------------+-------------+
Expand Down
4 changes: 4 additions & 0 deletions docs/source/AdministratorGuide/Tutorials/installTS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ Using the ``Configuration Manager`` application in the WebApp, create a new sect
After restarting the ``ProxyManager``, you should now be able to get a proxy belonging to the ``dirac_prod`` group that
will be automatically uploaded.

The ``ProductionManagement`` property allows users in the group to access and change all transformations. There is also
a ``ProductionSharing`` property to only allow access to transformations in the same group and ``ProductionUser`` to
only allow users to access their own transformations.

Add a ProdManager Shifter
=========================

Expand Down
6 changes: 5 additions & 1 deletion src/DIRAC/Core/Security/Properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,12 @@ class SecurityProperty(str, Enum):
PRIVATE_LIMITED_DELEGATION = "PrivateLimitedDelegation"
#: Allow managing proxies
PROXY_MANAGEMENT = "ProxyManagement"
#: Allow managing production
#: Allow managing all productions
PRODUCTION_MANAGEMENT = "ProductionManagement"
#: Allow managing all productions in the same group
PRODUCTION_SHARING = "ProductionSharing"
#: Allows user to manage productions they own only
PRODUCTION_USER = "ProductionUser"
#: Allow production request approval on behalf of PPG
PPG_AUTHORITY = "PPGAuthority"
#: Allow Bookkeeping Management
Expand Down
2 changes: 2 additions & 0 deletions src/DIRAC/FrameworkSystem/Client/ComponentInstaller.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
OPERATOR,
NORMAL_USER,
TRUSTED_HOST,
PRODUCTION_MANAGEMENT,
)

from DIRAC.ConfigurationSystem.Client import PathFinder
Expand Down Expand Up @@ -447,6 +448,7 @@ def _getCentralCfg(self, installCfg):
FULL_DELEGATION,
PROXY_MANAGEMENT,
OPERATOR,
PRODUCTION_MANAGEMENT,
]

for section in (
Expand Down
169 changes: 118 additions & 51 deletions src/DIRAC/TransformationSystem/Service/TransformationManagerHandler.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Command Line Parameters for creating the Replication transformations Script
"""
from DIRAC import S_OK, S_ERROR, gLogger
from DIRAC.Core.Security.Properties import SecurityProperty
from DIRAC.Core.Security.ProxyInfo import getProxyInfo
from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOMSVOForGroup

Expand Down Expand Up @@ -151,9 +152,13 @@ def _checkProxy(self):
groupProperties = proxyValues.get("groupProperties", [])

if groupProperties:
if "ProductionManagement" not in groupProperties:
if (
SecurityProperty.PRODUCTION_MANAGEMENT not in groupProperties
and SecurityProperty.PRODUCTION_SHARING not in groupProperties
and SecurityProperty.PRODUCTION_USER not in groupProperties
):
self.errorMessages.append(
"ERROR: Not allowed to create production, you need a ProductionManagement proxy."
"ERROR: Not allowed to create production, you need one of the Production properties."
)
return False
else:
Expand Down
127 changes: 127 additions & 0 deletions tests/Integration/TransformationSystem/Test_TS_CheckPerms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env python
""" This tests the TransformationManager checkPermission function
"""
import unittest
import functools
import sys

import DIRAC
from DIRAC import S_OK, S_ERROR

DIRAC.initialize() # Initialize configuration

from DIRAC.TransformationSystem.Service.TransformationManagerHandler import TransformationManagerHandlerMixin


class TSCheckPermTestCase(unittest.TestCase):
TEST_USERS = {
# Users a1/a2 are just regular tf users with no sharing
# a1 & a2 are in the same group
"user_a1": {"DN": "/CN=user_a1", "group": "group_a", "properties": ["ProductionUser"]},
"user_a2": {"DN": "/CN=user_a2", "group": "group_a", "properties": ["ProductionUser"]},
# Users b1/b2 have production sharing for their group
# b1 & b2 are in the same group
"user_b1": {"DN": "/CN=user_b1", "group": "group_b", "properties": ["ProductionSharing"]},
"user_b2": {"DN": "/CN=user_b2", "group": "group_b", "properties": ["ProductionSharing"]},
# Admin user has full ProductionManagement permission
"admin": {"DN": "/CN=dirac_admin", "group": "dirac_admin", "properties": ["ProductionManagement"]},
# Vistor has no tf permissions at all
"visitor": {"DN": "/CN=none", "group": "visitors", "properties": []},
}
TEST_TRANSFORMATIONS = {
# Each transformation is owned by the matching user
# e.g. user_a1 owns TF_A1 and so forth...
"TF_A1": {"AuthorDN": "/CN=user_a1", "AuthorGroup": "group_a"},
"TF_A2": {"AuthorDN": "/CN=user_a2", "AuthorGroup": "group_a"},
"TF_B1": {"AuthorDN": "/CN=user_b1", "AuthorGroup": "group_b"},
"TF_B2": {"AuthorDN": "/CN=user_b2", "AuthorGroup": "group_b"},
"TF_C1": {"AuthorDN": "/CN=user_c1", "AuthorGroup": "group_c"},
}
TEST_PERM_MATRIX = (
# User a1 should only be able to access their own tf
("user_a1", "TF_A1", True),
("user_a1", "TF_A2", False),
("user_a1", "TF_B1", False),
("user_a1", "TF_B2", False),
("user_a1", "TF_C1", False),
# User a2 should only be able to access their own tf
("user_a2", "TF_A1", False),
("user_a2", "TF_A2", True),
("user_a2", "TF_B1", False),
("user_a2", "TF_B2", False),
("user_a2", "TF_C1", False),
# User b1 should have access to all in the B group
("user_b1", "TF_A1", False),
("user_b1", "TF_A2", False),
("user_b1", "TF_B1", True),
("user_b1", "TF_B2", True),
("user_b1", "TF_C1", False),
# User b2 should have access to all in the B group
("user_b2", "TF_A1", False),
("user_b2", "TF_A2", False),
("user_b2", "TF_B1", True),
("user_b2", "TF_B2", True),
("user_b2", "TF_C1", False),
# Admin should have access to all
("admin", "TF_A1", True),
("admin", "TF_A2", True),
("admin", "TF_B1", True),
("admin", "TF_B2", True),
("admin", "TF_C1", True),
# Vistor should have access to none
("visitor", "TF_A1", False),
("visitor", "TF_A2", False),
("visitor", "TF_B1", False),
("visitor", "TF_B2", False),
("visitor", "TF_C1", False),
# Only admin should have access to a non-existant tfName
# (as admin is a short-circuit check that doesn't actually go to the DB)
("user_a1", "TF_ZZ", False),
("user_a2", "TF_ZZ", False),
("user_b1", "TF_ZZ", False),
("user_b2", "TF_ZZ", False),
("admin", "TF_ZZ", True),
("visitor", "TF_ZZ", False),
)

class _mockTFDatabase(object):
"""A class that mocks up the Transformation database."""

def getTransformation(self, tfName):
if tfName in TSCheckPermTestCase.TEST_TRANSFORMATIONS:
return S_OK(TSCheckPermTestCase.TEST_TRANSFORMATIONS[tfName])
return S_ERROR(f"Failed to find transformation {tfName}")

def _mockGetRemoteCredentials(self, tfmHandler):
"""Mocks up get remote credentails based on the current user."""
return self.currentUser

def _setUser(self, user):
"""Sets the current user for the mocked getRemoteCredentials function from the test dict."""
if user in self.TEST_USERS:
self.currentUser = self.TEST_USERS[user]
return
self.currentUser = self.TEST_USERS["visitor"]

def setUp(self):
"""Create TransformationManagerHandlerMixin and then replace the key functions directly
with the mocked up ones.
"""
self.handler = TransformationManagerHandlerMixin()
self.handler.getRemoteCredentials = functools.partial(self._mockGetRemoteCredentials, self)
self.handler.transformationDB = self._mockTFDatabase()
self._setUser(None)

def test_checkPerms(self):
for user, tfName, expRes in self.TEST_PERM_MATRIX:
self._setUser(user)
res = self.handler.checkPermissions(tfName)
self.assertEqual(
expRes, res["OK"], f"User {user} access to tf {tfName}: {res['OK']} but expected {expRes}."
)


if __name__ == "__main__":
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TSCheckPermTestCase)
testResult = unittest.TextTestRunner(verbosity=2).run(suite)
sys.exit(not testResult.wasSuccessful())
2 changes: 1 addition & 1 deletion tests/Jenkins/utilities.sh
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ diracUserAndGroup() {
exit 1
fi

if ! dirac-admin-add-group -G prod -U adminusername,ciuser,trialUser -P Operator,FullDelegation,ProxyManagement,ServiceAdministrator,JobAdministrator,CSAdministrator,AlarmsManagement,FileCatalogManagement,SiteManager,NormalUser,VmRpcOperation "${DEBUG}"; then
if ! dirac-admin-add-group -G prod -U adminusername,ciuser,trialUser -P Operator,FullDelegation,ProxyManagement,ServiceAdministrator,JobAdministrator,CSAdministrator,AlarmsManagement,FileCatalogManagement,SiteManager,NormalUser,VmRpcOperation,ProductionManagement "${DEBUG}"; then
echo 'ERROR: dirac-admin-add-group failed' >&2
exit 1
fi
Expand Down

0 comments on commit 410937b

Please sign in to comment.