DIRAC 9.0.0a42__py3-none-any.whl → 9.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
  2. DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
  3. DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
  4. DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
  5. DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
  6. DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
  7. DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +38 -26
  8. DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
  9. DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
  10. DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
  11. DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
  12. DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
  13. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +32 -19
  14. DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
  15. DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
  16. DIRAC/Core/Base/API.py +4 -7
  17. DIRAC/Core/Base/SQLAlchemyDB.py +1 -0
  18. DIRAC/Core/DISET/ServiceReactor.py +11 -3
  19. DIRAC/Core/DISET/private/BaseClient.py +1 -2
  20. DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
  21. DIRAC/Core/DISET/private/Transports/SSL/M2Utils.py +3 -1
  22. DIRAC/Core/LCG/GOCDBClient.py +5 -7
  23. DIRAC/Core/Security/DiracX.py +31 -17
  24. DIRAC/Core/Security/IAMService.py +5 -10
  25. DIRAC/Core/Security/Locations.py +27 -18
  26. DIRAC/Core/Security/ProxyInfo.py +9 -5
  27. DIRAC/Core/Security/VOMSService.py +2 -4
  28. DIRAC/Core/Security/m2crypto/X509Certificate.py +4 -6
  29. DIRAC/Core/Security/m2crypto/asn1_utils.py +17 -5
  30. DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
  31. DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
  32. DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
  33. DIRAC/Core/Utilities/CGroups2.py +328 -0
  34. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  35. DIRAC/Core/Utilities/DErrno.py +5 -309
  36. DIRAC/Core/Utilities/Extensions.py +10 -1
  37. DIRAC/Core/Utilities/File.py +1 -1
  38. DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
  39. DIRAC/Core/Utilities/Graphs/GraphUtilities.py +6 -1
  40. DIRAC/Core/Utilities/JDL.py +1 -195
  41. DIRAC/Core/Utilities/List.py +1 -124
  42. DIRAC/Core/Utilities/MySQL.py +103 -99
  43. DIRAC/Core/Utilities/Os.py +32 -1
  44. DIRAC/Core/Utilities/Platform.py +2 -107
  45. DIRAC/Core/Utilities/Proxy.py +0 -4
  46. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  47. DIRAC/Core/Utilities/StateMachine.py +12 -178
  48. DIRAC/Core/Utilities/Subprocess.py +35 -14
  49. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  50. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  51. DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
  52. DIRAC/Core/scripts/dirac_agent.py +1 -1
  53. DIRAC/Core/scripts/dirac_apptainer_exec.py +72 -46
  54. DIRAC/Core/scripts/dirac_configure.py +1 -3
  55. DIRAC/Core/scripts/dirac_install_db.py +24 -6
  56. DIRAC/Core/scripts/dirac_platform.py +1 -92
  57. DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
  58. DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
  59. DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
  60. DIRAC/DataManagementSystem/DB/FTS3DB.py +7 -3
  61. DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
  62. DIRAC/DataManagementSystem/DB/FileCatalogDB.sql +9 -9
  63. DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql +9 -9
  64. DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
  65. DIRAC/DataManagementSystem/scripts/dirac_admin_allow_se.py +13 -8
  66. DIRAC/DataManagementSystem/scripts/dirac_admin_ban_se.py +13 -8
  67. DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
  68. DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
  69. DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py +2 -7
  70. DIRAC/FrameworkSystem/Client/ComponentInstaller.py +9 -4
  71. DIRAC/FrameworkSystem/Client/ProxyManagerClient.py +5 -2
  72. DIRAC/FrameworkSystem/Client/SystemAdministratorClientCLI.py +11 -6
  73. DIRAC/FrameworkSystem/ConfigTemplate.cfg +2 -0
  74. DIRAC/FrameworkSystem/DB/AuthDB.py +3 -3
  75. DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +4 -4
  76. DIRAC/FrameworkSystem/DB/ProxyDB.py +11 -3
  77. DIRAC/FrameworkSystem/DB/TokenDB.py +1 -1
  78. DIRAC/FrameworkSystem/Service/ProxyManagerHandler.py +8 -6
  79. DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +2 -19
  80. DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
  81. DIRAC/FrameworkSystem/Utilities/diracx.py +36 -14
  82. DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
  83. DIRAC/FrameworkSystem/scripts/dirac_admin_update_pilot.py +18 -11
  84. DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
  85. DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +7 -8
  86. DIRAC/Interfaces/API/Dirac.py +27 -15
  87. DIRAC/Interfaces/API/DiracAdmin.py +45 -17
  88. DIRAC/Interfaces/API/Job.py +9 -13
  89. DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +12 -18
  90. DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +12 -10
  91. DIRAC/Interfaces/scripts/dirac_admin_get_site_mask.py +4 -13
  92. DIRAC/Interfaces/scripts/dirac_admin_reset_job.py +3 -6
  93. DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
  94. DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
  95. DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
  96. DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
  97. DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
  98. DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
  99. DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
  100. DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
  101. DIRAC/ProductionSystem/DB/ProductionDB.sql +4 -4
  102. DIRAC/ProductionSystem/scripts/dirac_prod_get.py +2 -2
  103. DIRAC/ProductionSystem/scripts/dirac_prod_get_all.py +2 -2
  104. DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
  105. DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
  106. DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py +2 -14
  107. DIRAC/RequestManagementSystem/Client/ReqClient.py +66 -13
  108. DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
  109. DIRAC/RequestManagementSystem/DB/RequestDB.py +10 -5
  110. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  111. DIRAC/RequestManagementSystem/private/RequestValidator.py +40 -46
  112. DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
  113. DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
  114. DIRAC/ResourceStatusSystem/DB/ResourceManagementDB.py +8 -8
  115. DIRAC/ResourceStatusSystem/DB/ResourceStatusDB.py +2 -2
  116. DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
  117. DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +30 -12
  118. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +195 -1
  119. DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py +181 -0
  120. DIRAC/Resources/Computing/AREXComputingElement.py +25 -8
  121. DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
  122. DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
  123. DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
  124. DIRAC/Resources/Computing/ComputingElement.py +1 -1
  125. DIRAC/Resources/Computing/HTCondorCEComputingElement.py +44 -44
  126. DIRAC/Resources/Computing/InProcessComputingElement.py +4 -2
  127. DIRAC/Resources/Computing/LocalComputingElement.py +1 -18
  128. DIRAC/Resources/Computing/SSHBatchComputingElement.py +1 -17
  129. DIRAC/Resources/Computing/SSHComputingElement.py +1 -18
  130. DIRAC/Resources/Computing/SingularityComputingElement.py +19 -5
  131. DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
  132. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  133. DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
  134. DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
  135. DIRAC/Resources/MessageQueue/StompMQConnector.py +1 -1
  136. DIRAC/Resources/Storage/GFAL2_StorageBase.py +24 -15
  137. DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py +1 -3
  138. DIRAC/Resources/Storage/StorageBase.py +4 -2
  139. DIRAC/Resources/Storage/StorageElement.py +6 -7
  140. DIRAC/StorageManagementSystem/DB/StorageManagementDB.sql +2 -2
  141. DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
  142. DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
  143. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +16 -16
  144. DIRAC/TransformationSystem/Client/TaskManager.py +2 -4
  145. DIRAC/TransformationSystem/Client/Transformation.py +6 -7
  146. DIRAC/TransformationSystem/Client/TransformationClient.py +21 -11
  147. DIRAC/TransformationSystem/Client/Utilities.py +9 -0
  148. DIRAC/TransformationSystem/DB/TransformationDB.py +11 -14
  149. DIRAC/TransformationSystem/DB/TransformationDB.sql +9 -9
  150. DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -333
  151. DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
  152. DIRAC/TransformationSystem/Utilities/TransformationInfo.py +7 -5
  153. DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
  154. DIRAC/TransformationSystem/test/Test_TransformationInfo.py +22 -15
  155. DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
  156. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  157. DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +38 -26
  158. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +12 -8
  159. DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
  160. DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
  161. DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +18 -14
  162. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
  163. DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
  164. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +45 -4
  165. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
  166. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  167. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +9 -2
  168. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
  169. DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +9 -9
  170. DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py +6 -6
  171. DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
  172. DIRAC/WorkloadManagementSystem/Client/JobReport.py +1 -1
  173. DIRAC/WorkloadManagementSystem/Client/JobState/CachedJobState.py +3 -0
  174. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  175. DIRAC/WorkloadManagementSystem/Client/JobState/JobState.py +6 -0
  176. DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
  177. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
  178. DIRAC/WorkloadManagementSystem/Client/PoolXMLSlice.py +12 -19
  179. DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
  180. DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
  181. DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
  182. DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
  183. DIRAC/WorkloadManagementSystem/DB/JobDB.py +89 -132
  184. DIRAC/WorkloadManagementSystem/DB/JobDB.sql +8 -8
  185. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  186. DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py +19 -6
  187. DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
  188. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +16 -5
  189. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql +3 -3
  190. DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +44 -82
  191. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  192. DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
  193. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  194. DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +5 -4
  195. DIRAC/WorkloadManagementSystem/Executor/JobScheduling.py +4 -0
  196. DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +75 -33
  197. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +22 -11
  198. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py +9 -10
  199. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +60 -10
  200. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  201. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
  202. DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
  203. DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
  204. DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -103
  205. DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +7 -53
  206. DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
  207. DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py +4 -18
  208. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -209
  209. DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
  210. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
  211. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  212. DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
  213. DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +41 -11
  214. DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
  215. DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
  216. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
  217. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -15
  218. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  219. DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
  220. DIRAC/WorkloadManagementSystem/scripts/dirac_jobexec.py +7 -2
  221. DIRAC/WorkloadManagementSystem/scripts/dirac_wms_pilot_job_info.py +1 -1
  222. DIRAC/__init__.py +62 -60
  223. DIRAC/tests/Utilities/testJobDefinitions.py +22 -28
  224. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/METADATA +8 -5
  225. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/RECORD +229 -228
  226. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
  227. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
  228. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  229. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  230. DIRAC/Resources/Computing/PilotBundle.py +0 -70
  231. DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
  232. DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
  233. DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
  234. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
  235. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info/licenses}/LICENSE +0 -0
  236. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  """ Collection of utilities for locating certs, proxy, CAs
2
2
  """
3
3
  import os
4
+
4
5
  import DIRAC
5
6
  from DIRAC import gConfig
6
7
 
@@ -24,12 +25,6 @@ def getProxyLocation():
24
25
  if os.path.isfile(f"/tmp/{proxyName}"):
25
26
  return f"/tmp/{proxyName}"
26
27
 
27
- # No gridproxy found
28
- return False
29
-
30
-
31
- # Retrieve CA's location
32
-
33
28
 
34
29
  def getCAsLocation():
35
30
  """Retrieve the CA's files location"""
@@ -63,22 +58,36 @@ def getCAsLocationNoConfig():
63
58
  casPath = "/etc/grid-security/certificates"
64
59
  if os.path.isdir(casPath):
65
60
  return casPath
66
- # No CA's location found
67
- return False
68
-
69
-
70
- # Retrieve CA's location
71
-
72
-
73
- def getCAsDefaultLocation():
74
- """Retrievethe CAs Location inside DIRAC etc directory"""
75
61
  # rootPath./etc/grid-security/certificates
76
62
  casPath = f"{DIRAC.rootPath}/etc/grid-security/certificates"
77
- return casPath
63
+ if os.path.isdir(casPath):
64
+ return casPath
78
65
 
79
66
 
80
- # TODO: Static depending on files specified on CS
81
- # Retrieve certificate
67
+ def getVOMSLocation():
68
+ """Retrieve the CA's files location"""
69
+ # Grid-Security
70
+ retVal = gConfig.getOption(f"{g_SecurityConfPath}/Grid-Security")
71
+ if retVal["OK"]:
72
+ vomsPath = f"{retVal['Value']}/vomsdir"
73
+ if os.path.isdir(vomsPath):
74
+ return vomsPath
75
+ # Look up the X509_VOMS_DIR environment variable
76
+ if "X509_VOMS_DIR" in os.environ:
77
+ vomsPath = os.environ["X509_VOMS_DIR"]
78
+ return vomsPath
79
+ # rootPath./etc/grid-security/vomsdir
80
+ vomsPath = f"{DIRAC.rootPath}/etc/grid-security/vomsdir"
81
+ if os.path.isdir(vomsPath):
82
+ return vomsPath
83
+ # /etc/grid-security/vomsdir
84
+ vomsPath = "/etc/grid-security/vomsdir"
85
+ if os.path.isdir(vomsPath):
86
+ return vomsPath
87
+ # rootPath./etc/grid-security/vomsdir
88
+ vomsPath = f"{DIRAC.rootPath}/etc/grid-security/vomsdir"
89
+ if os.path.isdir(vomsPath):
90
+ return vomsPath
82
91
 
83
92
 
84
93
  def getHostCertificateAndKeyLocation(specificLocation=None):
@@ -1,10 +1,13 @@
1
1
  """
2
- Set of utilities to retrieve Information from proxy
2
+ Set of utilities to retrieve Information from proxy
3
3
  """
4
+
4
5
  import base64
5
6
 
6
7
  from DIRAC import S_ERROR, S_OK, gLogger
7
8
  from DIRAC.ConfigurationSystem.Client.Helpers import Registry
9
+ from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
10
+
8
11
  from DIRAC.Core.Security import Locations
9
12
  from DIRAC.Core.Security.DiracX import diracxTokenFromPEM
10
13
  from DIRAC.Core.Security.VOMS import VOMS
@@ -207,10 +210,11 @@ def getVOfromProxyGroup():
207
210
  """
208
211
  Return the VO associated to the group in the proxy
209
212
  """
210
- voName = Registry.getVOForGroup("NoneExistingGroup")
213
+
211
214
  ret = getProxyInfo(disableVOMS=True)
212
- if not ret["OK"]:
213
- return S_OK(voName)
214
- if "group" in ret["Value"]:
215
+ if not ret["OK"] or "group" not in ret["Value"]:
216
+ voName = getVO()
217
+ else:
215
218
  voName = Registry.getVOForGroup(ret["Value"]["group"])
219
+
216
220
  return S_OK(voName)
@@ -64,8 +64,6 @@ class VOMSService:
64
64
  if not self.urls:
65
65
  return S_ERROR(DErrno.ENOAUTH, "No VOMS server defined")
66
66
 
67
- userProxy = getProxyLocation()
68
- caPath = getCAsLocation()
69
67
  rawUserList = []
70
68
  result = None
71
69
  for url in self.urls:
@@ -79,8 +77,8 @@ class VOMSService:
79
77
  result = requests.get(
80
78
  url,
81
79
  headers={"X-VOMS-CSRF-GUARD": "y"},
82
- cert=userProxy,
83
- verify=caPath,
80
+ cert=getProxyLocation(),
81
+ verify=getCAsLocation(),
84
82
  params={"startIndex": str(startIndex), "pageSize": "100"},
85
83
  )
86
84
  except requests.ConnectionError as exc:
@@ -99,13 +99,11 @@ class X509Certificate:
99
99
  proxySubject = M2Crypto.X509.X509_Name()
100
100
 
101
101
  issuerSubjectObj = x509Issuer.__certObj.get_subject()
102
- # pylint: disable=no-member
103
- issuerSubjectParts = issuerSubjectObj.as_text(flags=M2Crypto.m2.XN_FLAG_RFC2253).split(",")
104
102
 
105
- # XN_FLAG_RFC2253 prints in reverse order but DIRAC has historically used the standard order
106
- for isPart in issuerSubjectParts[::-1]:
107
- nid, val = isPart.split("=", 1)
108
- proxySubject.add_entry_by_txt(field=nid, type=M2Crypto.ASN1.MBSTRING_ASC, entry=val, len=-1, loc=-1, set=0)
103
+ # Copy the X509 entry components into the new name
104
+ for entry in issuerSubjectObj:
105
+ # pylint: disable=no-member
106
+ M2Crypto.m2.x509_name_add_entry(proxySubject.x509_name, entry.x509_name_entry, -1, 0)
109
107
 
110
108
  # Finally we add a random Common Name component. And we might as well use the serial.. :)
111
109
  proxySubject.add_entry_by_txt(
@@ -14,6 +14,8 @@ This is now pure python, but it might be interesting to wrap the existing
14
14
  C library (https://github.com/italiangrid/voms) instead...
15
15
 
16
16
  """
17
+ from functools import lru_cache
18
+
17
19
  from pyasn1.codec.der.decoder import decode as der_decode
18
20
  from pyasn1.error import PyAsn1Error
19
21
  from pyasn1.type import namedtype, univ, char as asn1char
@@ -93,6 +95,11 @@ def decodeDIRACGroup(m2cert):
93
95
  """
94
96
 
95
97
  diracGroupOctetString = retrieveExtension(m2cert, DIRAC_GROUP_OID)
98
+ return _decodeDIRACGroup(diracGroupOctetString)
99
+
100
+
101
+ @lru_cache
102
+ def _decodeDIRACGroup(diracGroupOctetString):
96
103
  diracGroupUTF8Str, _rest = der_decode(diracGroupOctetString, asn1Spec=asn1char.IA5String())
97
104
 
98
105
  return diracGroupUTF8Str.asOctets().decode()
@@ -336,11 +343,7 @@ def retrieveExtension(m2Cert, extensionOID):
336
343
 
337
344
  :raises: LookupError if it does not have the extension
338
345
  """
339
-
340
- # Decode the certificate as a RFC2459 Certificate object.It is compatible
341
- # with the RFC proxy definition
342
- cert, _rest = der_decode(m2Cert.as_der(), asn1Spec=rfc2459.Certificate())
343
- extensions = cert["tbsCertificate"]["extensions"]
346
+ extensions = _extensionsFromCertDER(m2Cert.as_der())
344
347
 
345
348
  # Construct an OID object for comparison purpose
346
349
  extensionOIDObj = univ.ObjectIdentifier(extensionOID)
@@ -354,3 +357,12 @@ def retrieveExtension(m2Cert, extensionOID):
354
357
 
355
358
  # If we are here, it means that we could not find the expected extension.
356
359
  raise LookupError(f"Could not find extension with OID {extensionOID}")
360
+
361
+
362
+ @lru_cache(maxsize=1024)
363
+ def _extensionsFromCertDER(der):
364
+ # Decode the certificate as a RFC2459 Certificate object.It is compatible
365
+ # with the RFC proxy definition
366
+ cert, _rest = der_decode(der, asn1Spec=rfc2459.Certificate())
367
+ extensions = cert["tbsCertificate"]["extensions"]
368
+ return extensions
@@ -0,0 +1,161 @@
1
+ import base64
2
+ import json
3
+ import pytest
4
+ import tempfile
5
+ from pathlib import Path
6
+ from unittest.mock import patch, mock_open
7
+
8
+ from DIRAC.Core.Security.DiracX import diracxTokenFromPEM, PEM_BEGIN, PEM_END, RE_DIRACX_PEM
9
+
10
+
11
+ class TestDiracxTokenFromPEM:
12
+ """Test cases for diracxTokenFromPEM function"""
13
+
14
+ def create_valid_token_data(self):
15
+ """Create valid token data for testing"""
16
+ return {
17
+ "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.test",
18
+ "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.refresh",
19
+ "expires_in": 3600,
20
+ "token_type": "Bearer",
21
+ }
22
+
23
+ def create_pem_content(self, token_data=None, include_other_content=True):
24
+ """Create PEM content with embedded DiracX token"""
25
+ if token_data is None:
26
+ token_data = self.create_valid_token_data()
27
+
28
+ # Encode token data
29
+ token_json = json.dumps(token_data)
30
+ encoded_token = base64.b64encode(token_json.encode("utf-8")).decode()
31
+
32
+ # Create PEM content
33
+ pem_content = ""
34
+ if include_other_content:
35
+ pem_content += "-----BEGIN CERTIFICATE-----\n"
36
+ pem_content += "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n"
37
+ pem_content += "-----END CERTIFICATE-----\n"
38
+
39
+ pem_content += f"{PEM_BEGIN}\n"
40
+ pem_content += encoded_token + "\n"
41
+ pem_content += f"{PEM_END}\n"
42
+
43
+ return pem_content
44
+
45
+ def test_valid_token_extraction(self):
46
+ """Test successful extraction of valid token from PEM file"""
47
+ token_data = self.create_valid_token_data()
48
+ pem_content = self.create_pem_content(token_data)
49
+
50
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
51
+ f.write(pem_content)
52
+ temp_path = f.name
53
+
54
+ try:
55
+ result = diracxTokenFromPEM(temp_path)
56
+ assert result == token_data
57
+ finally:
58
+ Path(temp_path).unlink()
59
+
60
+ def test_no_token_in_pem(self):
61
+ """Test behavior when no DiracX token is present in PEM file"""
62
+ pem_content = """-----BEGIN CERTIFICATE-----
63
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
64
+ -----END CERTIFICATE-----"""
65
+
66
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
67
+ f.write(pem_content)
68
+ temp_path = f.name
69
+
70
+ try:
71
+ result = diracxTokenFromPEM(temp_path)
72
+ assert result is None
73
+ finally:
74
+ Path(temp_path).unlink()
75
+
76
+ def test_multiple_tokens_error(self):
77
+ """Test that multiple tokens raise ValueError"""
78
+ token_data = self.create_valid_token_data()
79
+
80
+ # Create PEM with two tokens
81
+ pem_content = self.create_pem_content(token_data)
82
+ pem_content += "\n" + self.create_pem_content(token_data, include_other_content=False)
83
+
84
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
85
+ f.write(pem_content)
86
+ temp_path = f.name
87
+
88
+ try:
89
+ with pytest.raises(ValueError, match="Found multiple DiracX tokens"):
90
+ diracxTokenFromPEM(temp_path)
91
+ finally:
92
+ Path(temp_path).unlink()
93
+
94
+ def test_malformed_base64(self):
95
+ """Test behavior with malformed base64 data"""
96
+ pem_content = f"""{PEM_BEGIN}
97
+ invalid_base64_data_that_will_cause_error!
98
+ {PEM_END}"""
99
+
100
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
101
+ f.write(pem_content)
102
+ temp_path = f.name
103
+
104
+ try:
105
+ with pytest.raises(Exception): # base64.b64decode will raise an exception
106
+ diracxTokenFromPEM(temp_path)
107
+ finally:
108
+ Path(temp_path).unlink()
109
+
110
+ def test_invalid_json_in_token(self):
111
+ """Test behavior with invalid JSON in token data"""
112
+ invalid_json = "this is not valid json"
113
+ encoded_invalid = base64.b64encode(invalid_json.encode("utf-8")).decode()
114
+
115
+ pem_content = f"""{PEM_BEGIN}
116
+ {encoded_invalid}
117
+ {PEM_END}"""
118
+
119
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
120
+ f.write(pem_content)
121
+ temp_path = f.name
122
+
123
+ try:
124
+ with pytest.raises(json.JSONDecodeError):
125
+ diracxTokenFromPEM(temp_path)
126
+ finally:
127
+ Path(temp_path).unlink()
128
+
129
+ def test_token_with_unicode_characters(self):
130
+ """Test token with unicode characters"""
131
+ unicode_token = {
132
+ "access_token": "token_with_unicode_ñ_é_ü",
133
+ "refresh_token": "refresh_with_emoji_🚀_🎉",
134
+ "expires_in": 3600,
135
+ "token_type": "Bearer",
136
+ }
137
+
138
+ pem_content = self.create_pem_content(unicode_token)
139
+
140
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".pem") as f:
141
+ f.write(pem_content)
142
+ temp_path = f.name
143
+
144
+ try:
145
+ result = diracxTokenFromPEM(temp_path)
146
+ assert result == unicode_token
147
+ finally:
148
+ Path(temp_path).unlink()
149
+
150
+ def test_regex_pattern_validation(self):
151
+ """Test that the regex pattern correctly identifies DiracX tokens"""
152
+ # Test that the regex matches the expected pattern
153
+ token_data = self.create_valid_token_data()
154
+ token_json = json.dumps(token_data)
155
+ encoded_token = base64.b64encode(token_json.encode("utf-8")).decode()
156
+
157
+ test_content = f"{PEM_BEGIN}\n{encoded_token}\n{PEM_END}"
158
+ matches = RE_DIRACX_PEM.findall(test_content)
159
+
160
+ assert len(matches) == 1
161
+ assert matches[0] == encoded_token
@@ -17,7 +17,6 @@ from DIRAC.Core.DISET.RPCClient import RPCClient
17
17
  from DIRAC.Core.DISET.TransferClient import TransferClient
18
18
  from DIRAC.Core.Tornado.Client.TornadoClient import TornadoClient
19
19
 
20
-
21
20
  sLog = gLogger.getSubLogger(__name__)
22
21
 
23
22
 
@@ -82,6 +81,10 @@ def ClientSelector(disetClient, *args, **kwargs): # We use same interface as RP
82
81
  rpc = tornadoClient(*args, **kwargs)
83
82
  else:
84
83
  rpc = disetClient(*args, **kwargs)
84
+ except NotImplementedError as e:
85
+ # We catch explicitly NotImplementedError to avoid just printing "there's an error"
86
+ # If we mis-configured the CS for legacy adapted services, we MUST have an error.
87
+ raise e
85
88
  except Exception as e: # pylint: disable=broad-except
86
89
  # If anything went wrong in the resolution, we return default RPCClient
87
90
  # So the behaviour is exactly the same as before implementation of Tornado
@@ -73,7 +73,7 @@ class TornadoService(BaseRequestHandler): # pylint: disable=abstract-method
73
73
  :py:class:`BaseRequestHandler <DIRAC.Core.Tornado.Server.private.BaseRequestHandler.BaseRequestHandler>` for more details.
74
74
 
75
75
  In order to pass information around and keep some states, we use instance attributes.
76
- These are initialized in the :py:meth:`.initialize` method.
76
+ These are initialized in the ``initialize`` methods.
77
77
 
78
78
  The handler only define the ``post`` verb. Please refer to :py:meth:`.post` for the details.
79
79