From 6f54fbc4a23e37dda6f2a548e49f700c77f8ac07 Mon Sep 17 00:00:00 2001 From: cinziaLu Date: Fri, 16 Sep 2016 10:22:27 +0200 Subject: [PATCH 1/3] - RESTDIRAC accepts host certificate to generate a token. - CS API to contact the CS using a token. - CS API test script --- .../Client/Helpers/RESTConf.py | 3 ++ RESTSystem/API/CS/CSHandler.py | 36 ++++++++++++++++++ RESTSystem/API/CS/__init__.py | 0 RESTSystem/API/oa2/TokenHandler.py | 15 +++++++- RESTSystem/Base/RESTHandler.py | 3 +- RESTSystem/DB/OATokenDB.py | 9 ++++- RESTSystem/Test/CStest.py | 38 +++++++++++++++++++ 7 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 RESTSystem/API/CS/CSHandler.py create mode 100644 RESTSystem/API/CS/__init__.py create mode 100644 RESTSystem/Test/CStest.py diff --git a/ConfigurationSystem/Client/Helpers/RESTConf.py b/ConfigurationSystem/Client/Helpers/RESTConf.py index fa064c5..02f661d 100644 --- a/ConfigurationSystem/Client/Helpers/RESTConf.py +++ b/ConfigurationSystem/Client/Helpers/RESTConf.py @@ -48,6 +48,9 @@ def key(): def setup(): return gConfig.getValue( "/DIRAC/Setup" ) +def getValue( path ): + return gConfig.getValue( path ) + def generateCAFile(): """ Generate a single CA file with all the PEMs diff --git a/RESTSystem/API/CS/CSHandler.py b/RESTSystem/API/CS/CSHandler.py new file mode 100644 index 0000000..57abe7f --- /dev/null +++ b/RESTSystem/API/CS/CSHandler.py @@ -0,0 +1,36 @@ +import types +import os +import shutil +import json +from tornado import web, gen +from RESTDIRAC.RESTSystem.Base.RESTHandler import WErr, WOK, TmpDir, RESTHandler +from RESTDIRAC.ConfigurationSystem.Client.Helpers import RESTConf + +class CSHandler( RESTHandler ): + + ROUTE = "/config/(Sections|Options|Value)" + + @web.asynchronous + def get( self, reqType ): + if reqType == "Sections": + return self.SectionsAction() + elif reqType == "Options": + return self.OptionsAction() + elif reqType == "Value": + return self.ValueAction() + + + @gen.engine + def ValueAction( self ): + args = self.request.arguments + try: + path = args[ 'ValuePath' ][0] + except KeyError: + self.send_error( 400 ) + return + condDict = {} + if 'allOwners' not in self.request.arguments: + condDict[ 'Owner' ] = self.getUserName() + result = RESTConf.getValue( path ) + self.finish( result ) + \ No newline at end of file diff --git a/RESTSystem/API/CS/__init__.py b/RESTSystem/API/CS/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/RESTSystem/API/oa2/TokenHandler.py b/RESTSystem/API/oa2/TokenHandler.py index a1a4bfd..c263034 100644 --- a/RESTSystem/API/oa2/TokenHandler.py +++ b/RESTSystem/API/oa2/TokenHandler.py @@ -75,12 +75,19 @@ def __getGroups( self, DN = False ): return WErr( 401, "No certificate received to issue a token" ) DN = credDict[ 'subject' ] if not credDict[ 'validDN' ]: - return WErr( 401, "Unknown DN %s" % DN ) + return WErr( 401, "Unknown DN %s" % DN ) result = Registry.getGroupsForDN( DN ) if not result[ 'OK' ]: return WErr( 500, result[ 'Message' ] ) return WOK( { 'groups' : result[ 'Value' ] } ) + def __getHostProperties ( self, group, DN ): + result = Registry.getPropertiesForEntity( group, dn = DN ) + if not result: + return WErr( 500, "Can't get the Property for the host" ) + return WOK( { 'groups' : result} ) + + def groupsAction( self ): result = self.__getGroups() if not result.ok: @@ -140,7 +147,11 @@ def __clientCredentialsRequest( self ): if not credDict[ 'validDN' ]: return WErr( 401, "Unknown DN %s" % DN ) #Check group - result = self.__getGroups( DN ) + if credDict.has_key( 'group' ): + if credDict['group'] == 'hosts': + result = self.__getHostProperties( 'hosts', DN ) + else: + result = self.__getGroups( DN ) if not result.ok: return result groups = result.data[ 'groups' ] diff --git a/RESTSystem/Base/RESTHandler.py b/RESTSystem/Base/RESTHandler.py index 13e1cbe..da0c652 100644 --- a/RESTSystem/Base/RESTHandler.py +++ b/RESTSystem/Base/RESTHandler.py @@ -155,6 +155,8 @@ def prepare( self ): self.send_error( 401 ) else: data = result[ 'Value' ] + if data[ 'UserGroup' ] == 'TrustedHost': + data[ 'UserGroup' ] = 'hosts' self.__uData = { 'DN' : data[ 'UserDN' ], 'username' : data[ 'UserName' ], 'group' : data[ 'UserGroup' ], @@ -166,7 +168,6 @@ def prepare( self ): self.log.info( "Setting DISET for %s" % cs ) elif self.REQUIRE_ACCESS: raise WErr( 401, "No token provided" ) - self.end_prepare() diff --git a/RESTSystem/DB/OATokenDB.py b/RESTSystem/DB/OATokenDB.py index 062b4c9..d325fd8 100755 --- a/RESTSystem/DB/OATokenDB.py +++ b/RESTSystem/DB/OATokenDB.py @@ -71,7 +71,7 @@ def __initializeDB( self ): 'Code' : 'CHAR(28)', 'Secret' : 'CHAR(28)', 'ClientID' : 'CHAR(28)', - 'UserName': 'VARCHAR(16) NOT NULL', + 'UserName': 'VARCHAR(32) NOT NULL', 'UserDN': 'VARCHAR(128) NOT NULL', 'UserGroup': 'VARCHAR(16) NOT NULL', 'UserSetup': 'VARCHAR(32) NOT NULL', @@ -292,7 +292,12 @@ def generateToken( self, userDN, userGroup, userSetup, scope = "", cid = False, if code: inData[ 'Code' ] = code - result = Registry.getUsernameForDN( userDN ) + if userGroup == 'TrustedHost': + result = Registry.getHostnameForDN( userDN ) + print "ecco hostname" + print result['Value'] + else: + result = Registry.getUsernameForDN( userDN ) if not result[ 'OK' ]: return result inData[ 'UserName' ] = result[ 'Value' ] diff --git a/RESTSystem/Test/CStest.py b/RESTSystem/Test/CStest.py new file mode 100644 index 0000000..5e7e54e --- /dev/null +++ b/RESTSystem/Test/CStest.py @@ -0,0 +1,38 @@ +import requests +import json +import os + +# The REST server url +REST_URL = 'https://0.0.0.0:9910' + +########################################### +# Get the access token first + +# GET request parameters +params = {'grant_type':'client_credentials', + 'group':'TrustedHost', + 'setup':'LHCb-Certification'} + +# The user certificate, password will be asked for to the user +# before request submission +#certificate = ('/home/cinzia/.globus/usercert.pem', +# '/home/cinzia/.globus/userkey.pem') + + +certificate = ('/home/cinzia/devRoot/etc/grid-security/hostcert.pem','/home/cinzia/devRoot/etc/grid-security/hostkey.pem') +proxies=('/tmp/x509up_u1000','/tmp/x509up_u1000') + +#result = requests.get(REST_URL+"/oauth2/token",params=params,cert=proxies, verify=False) +result = requests.get(REST_URL+"/oauth2/token",params=params,cert=certificate,verify=False) + + +# the output is returned as a json encoded string, decode it here +resultDict = json.loads( result.text ) +access_token = resultDict['token'] + +JobHistory = requests.get(REST_URL+'/jobs/history',params={'access_token':access_token}, + verify=False) + +PilotCommands = requests.get(REST_URL+'/config/Value',params={'access_token':access_token,'ValuePath':'/Operations/LHCb-Certification/Pilot/Commands/BOINC'}, verify=False) + +######################################## From b7c0cf48e87230e0cb6c32b1423e9e7e95d48cc6 Mon Sep 17 00:00:00 2001 From: cinziaLu Date: Fri, 16 Sep 2016 10:36:33 +0200 Subject: [PATCH 2/3] Delete print --- RESTSystem/API/CS/CSHandler.py | 3 +-- RESTSystem/DB/OATokenDB.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/RESTSystem/API/CS/CSHandler.py b/RESTSystem/API/CS/CSHandler.py index 57abe7f..7a0a605 100644 --- a/RESTSystem/API/CS/CSHandler.py +++ b/RESTSystem/API/CS/CSHandler.py @@ -32,5 +32,4 @@ def ValueAction( self ): if 'allOwners' not in self.request.arguments: condDict[ 'Owner' ] = self.getUserName() result = RESTConf.getValue( path ) - self.finish( result ) - \ No newline at end of file + self.finish( result ) \ No newline at end of file diff --git a/RESTSystem/DB/OATokenDB.py b/RESTSystem/DB/OATokenDB.py index d325fd8..fecef69 100755 --- a/RESTSystem/DB/OATokenDB.py +++ b/RESTSystem/DB/OATokenDB.py @@ -294,8 +294,6 @@ def generateToken( self, userDN, userGroup, userSetup, scope = "", cid = False, if userGroup == 'TrustedHost': result = Registry.getHostnameForDN( userDN ) - print "ecco hostname" - print result['Value'] else: result = Registry.getUsernameForDN( userDN ) if not result[ 'OK' ]: From a931dd079a7a0e4f27f4e744caa7acd66ade05b4 Mon Sep 17 00:00:00 2001 From: cinziaLu Date: Thu, 29 Sep 2016 09:34:24 +0200 Subject: [PATCH 3/3] Fix --- RESTSystem/API/CS/CSHandler.py | 8 ++------ RESTSystem/API/oa2/TokenHandler.py | 2 +- RESTSystem/Test/CStest.py | 11 ++++++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/RESTSystem/API/CS/CSHandler.py b/RESTSystem/API/CS/CSHandler.py index 7a0a605..223bad9 100644 --- a/RESTSystem/API/CS/CSHandler.py +++ b/RESTSystem/API/CS/CSHandler.py @@ -1,9 +1,5 @@ -import types -import os -import shutil -import json from tornado import web, gen -from RESTDIRAC.RESTSystem.Base.RESTHandler import WErr, WOK, TmpDir, RESTHandler +from RESTDIRAC.RESTSystem.Base.RESTHandler import RESTHandler from RESTDIRAC.ConfigurationSystem.Client.Helpers import RESTConf class CSHandler( RESTHandler ): @@ -32,4 +28,4 @@ def ValueAction( self ): if 'allOwners' not in self.request.arguments: condDict[ 'Owner' ] = self.getUserName() result = RESTConf.getValue( path ) - self.finish( result ) \ No newline at end of file + self.finish( result ) diff --git a/RESTSystem/API/oa2/TokenHandler.py b/RESTSystem/API/oa2/TokenHandler.py index c263034..b561fcb 100644 --- a/RESTSystem/API/oa2/TokenHandler.py +++ b/RESTSystem/API/oa2/TokenHandler.py @@ -147,7 +147,7 @@ def __clientCredentialsRequest( self ): if not credDict[ 'validDN' ]: return WErr( 401, "Unknown DN %s" % DN ) #Check group - if credDict.has_key( 'group' ): + if 'group' in credDict: if credDict['group'] == 'hosts': result = self.__getHostProperties( 'hosts', DN ) else: diff --git a/RESTSystem/Test/CStest.py b/RESTSystem/Test/CStest.py index 5e7e54e..cfcc0a4 100644 --- a/RESTSystem/Test/CStest.py +++ b/RESTSystem/Test/CStest.py @@ -1,6 +1,11 @@ +""" +Test script that ask a token to the REST SERVER using a trusted host certificate. +Gets the job history using the token. +Gets the pilot commands using the token. +""" import requests import json -import os + # The REST server url REST_URL = 'https://0.0.0.0:9910' @@ -20,9 +25,9 @@ certificate = ('/home/cinzia/devRoot/etc/grid-security/hostcert.pem','/home/cinzia/devRoot/etc/grid-security/hostkey.pem') -proxies=('/tmp/x509up_u1000','/tmp/x509up_u1000') +# proxies=('/tmp/x509up_u1000','/tmp/x509up_u1000') +# result = requests.get(REST_URL+"/oauth2/token",params=params,cert=proxies, verify=False) -#result = requests.get(REST_URL+"/oauth2/token",params=params,cert=proxies, verify=False) result = requests.get(REST_URL+"/oauth2/token",params=params,cert=certificate,verify=False)