Пример: Применение прав доступа к сервису из текстового файла
Этот скрипт считывает список прав доступа из предоставляемого вами текстового файла с разделителями в виде вертикальной линии и применяет эти права доступа к вашим сервисам. Список предоставляется вами в этом формате:
#resourceName|resourceType|permissions
resourceName=Rainier/Fauna|permissions=rangers,volunteers
resourceName=Roads|permissions=public
resourceName=BufferGeoprocessing|permissions=rangers,volunteers,visitors
resourceName=Geocode|permissions=rangers,volunteers,visitors
resourceName=ServiceArea|permissions=allLoggedInUsers
resourceName=Yosemite|resourceType=folder|permissions=visitors
resourceName=Parks/Yosemite|resourceType=service|permissions=rangers
- resourceName – название сервиса, работающего на ArcGIS Server. Использование / означает, что данный сервис находится в папке.
- resourceType – используется только для того, чтобы пояснить, что папка и сервис имеют одинаковые названия. Значениями являются service или folder.
- permissions – список разделенных запятыми ролей ArcGIS Server, которые должны получить права доступа к данному сервису. Имеются две специальные роли: allLoggedInUsers дает права доступа каждому подключившемуся с именем пользователя, которое имеется в пользовательском хранилище ArcGIS Server; роль public дает право доступа любому – как подключившемуся, так и не подключившемуся. Обе эти роли работают только на серверах, конфигурация которых предполагает аутентификацию на основе токенов.
Не поименованные в текстовом файле сервисы остаются открытыми для общего доступа.
import json, urllib,httplib
import sys
import getpass
import codecs
def main(argv=None):
# Ask for admin user name and password
username = raw_input("Enter user name: ")
password = getpass.getpass("Enter password: ")
# Ask for server name & port
serverName = raw_input("Enter server name: ")
serverPort = raw_input("Enter server port: ")
# Get a token and connect
token = getToken(username, password, serverName, serverPort)
if token == "":
sys.exit(1)
# Input file that contains the resources and permissions
permissionsFile = raw_input("Path to comma-delimited text file containing resources and permissions: ")
permissions = {}
num = 0
for permissionsRow in readlinesFromInputFile(permissionsFile):
permissionsEntry = {}
for index in range(len(permissionsRow)):
permissionsProp = permissionsRow[index].split("=")
if permissionsProp[0] == "resourceName":
permissionsEntry["resourceName"] = permissionsProp[1]
if permissionsProp[0] == "resourceType":
permissionsEntry["resourceType"] = permissionsProp[1]
if permissionsProp[0] == "permissions":
permissionsEntry["permissions"] = permissionsProp[1]
# Add the services information to a dictionary
permissions["resource" + str(num)] = permissionsEntry
num +=1
# Call helper function to add permissions on the given resources
assignPermissions(permissions,serverName,serverPort,token)
# A function that reads lines from the input file
def readlinesFromInputFile(filename, delim='|'):
file = codecs.open(filename,'r','utf-8-sig')
for line in file.readlines():
# Remove the trailing whitespaces and the newline characters
line = line.rstrip()
if line.startswith('#') or len(line) == 0:
pass # Skip the lines that contain # at the beginning or any empty lines
else:
# Split the current line into list
yield line.split(delim)
file.close()
def assignPermissions(permissionsDict,serverName,serverPort,token):
for permissionToAdd in permissionsDict:
permissionRow = permissionsDict[permissionToAdd]
if ((not 'resourceName' in permissionRow) or (not 'permissions' in permissionRow)):
# either resourceName or permissions are missing from the row, so skipping the row
continue
if 'resourceType' in permissionRow: # User provided the resourceType in the input file
resourceType = permissionRow['resourceType']
else: # User did not provide the resourceType in the input file
resourceType = ""
## Permissions (Roles) are a comma separated list, we need to split the permissions(roles) using a comma
permissions = permissionRow['permissions'].split(',')
# Check if the special role "public" is specified
if 'public' in permissions:
if (isTokenBasedAuth): # public special role is applicable only when token based authentication is configured on the server
applyPermission(permissionRow['resourceName'],resourceType,'public',True,token,serverName,serverPort)
continue
# Check if the special role "allLoggedInUsers" is specified
if 'allLoggedInUsers' in permissions:
if (isTokenBasedAuth): # allLoggedInUsers special role applicable only when token based authentication is configured on the server
applyPermission(permissionRow['resourceName'],resourceType,'allLoggedInUsers',True,token,serverName,serverPort)
# remove public access on the resource if present
if (checkIfRolePresentOnResource(permissionRow['resourceName'],resourceType,'public',token,serverName,serverPort)):
applyPermission(permissionRow['resourceName'],resourceType,'public',False,token,serverName,serverPort)
continue
# Loop through all the roles (in a comma separated list of roles/permissions) and add them to the resources
for index in range(len(permissions)):
role = permissions[index]
if (checkIfRoleExistsInRoleStore(role,token,serverName,serverPort)):
applyPermission(permissionRow['resourceName'],resourceType,role,True,token,serverName,serverPort)
else:
print "The permission '" + role + "' does not exist in the server."
continue
# Verify that at least one of the roles in the list of roles is added to the resource successfully, if yes we can remove public/allLoggedInUsers (if present) roles from the resource
appliedPermissionSuccessfully = False
for index in range(len(permissions)):
permission = permissions[index]
if (checkIfRolePresentOnResource(permissionRow['resourceName'],resourceType,permission,token,serverName,serverPort)):
# We verified that at least one permission has been applied successfully, so we can break and check/remove public access from the resource
appliedPermissionSuccessfully = True
break
if (appliedPermissionSuccessfully):
# remove public access on the resource if present
if (checkIfRolePresentOnResource(permissionRow['resourceName'],resourceType,'public',token,serverName,serverPort)):
applyPermission(permissionRow['resourceName'],resourceType,'public',False,token,serverName,serverPort)
# remove allLoggedInUsers role on the resource if present
if (checkIfRolePresentOnResource(permissionRow['resourceName'],resourceType,'allLoggedInUsers',token,serverName,serverPort)):
applyPermission(permissionRow['resourceName'],resourceType,'allLoggedInUsers',False,token,serverName,serverPort)
def applyPermission(resourceName,resourceType,role,isAllowed,token,serverName,serverPort):
if (role == 'public'):
params = urllib.urlencode({'token':token,'f':'json','principal':'esriEveryone','isAllowed':isAllowed})
else:
if (role == 'allLoggedInUsers'):
params = urllib.urlencode({'token':token,'f':'json','principal':'esriAuthenticated','isAllowed':isAllowed})
else:
params = urllib.urlencode({'token':token,'f':'json','principal':role,'isAllowed':isAllowed})
## Find the resource URL
resourceURL = None
if (resourceType == ""): # User did not provide the resourceType, so we need to find out by making admin calls
resourceTypeAndURL = getResourceTypeAndURL(resourceName,serverName,serverPort,token)
resourceURL = resourceTypeAndURL[1]
resourceType = resourceTypeAndURL[0]
else: ## this means user has explicitly provided the resourceType in the input file
if (resourceType == 'folder'):
resourceURL = "/arcgis/admin/services/"+resourceName+"/permissions/"
elif(resourceType == 'service'):
## it is a service, so we need to find its type
serviceType = getServiceType(resourceName,serverName,serverPort,token)
if serviceType is not None:
resourceURL = "/arcgis/admin/services/"+resourceName+"."+serviceType+"/permissions/"
if (resourceURL is not None):
resourceURL = resourceURL+"/add"
response, data = postToServer(serverName, serverPort, resourceURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
if (isAllowed):
print "Unable to assign the permission '" + role + "' on the " + resourceType + " '" + resourceName + "'"
print str(data)
else:
if (isAllowed):
print "Successfully assigned the permission '" + role + "' on the " + resourceType + " '" + resourceName + "'"
else:
print "Unable to find the resource: '" + resourceName + "' on the server."
def checkIfRolePresentOnResource(resourceName,resourceType,role,token,serverName,serverPort):
params = urllib.urlencode({'token':token,'f':'json'})
if (role == 'public'):
role = 'esriEveryone'
elif (role == 'allLoggedInUsers'):
role = 'esriAuthenticated'
## Find the resource URL
resourceURL = None
if (resourceType == ""): # User did not provide the resourceType, so we need to find out by making admin calls
resourceTypeAndURL = getResourceTypeAndURL(resourceName,serverName,serverPort,token)
resourceURL = resourceTypeAndURL[1]
resourceType = resourceTypeAndURL[0]
else: ## this means user has explicitly provided the resourceType in the input file
if (resourceType == 'folder'):
resourceURL = "/arcgis/admin/services/"+resourceName+"/permissions/"
elif(resourceType == 'service'):
## it is a service, so we need to find its type
serviceType = getServiceType(resourceName,serverName,serverPort,token)
if serviceType is not None:
resourceURL = "/arcgis/admin/services/"+resourceName+"."+serviceType+"/permissions/"
if (resourceURL is not None):
response, data = postToServer(serverName, serverPort, resourceURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Unable to check if the permission '" + role + "' exists on the " + resourceType + " '" + resourceName + "'"
print str(data)
return
else:
prmsJSON = json.loads(data)
prms = prmsJSON['permissions']
for prm in prms :
if (('principal' in prm) and (codecs.decode(prm['principal'],'utf-8') == role)):
return True
return False
def checkIfRoleExistsInRoleStore(role,token,serverName,serverPort):
params = urllib.urlencode({'token':token,'f':'json'})
## Find the resource URL
resourceURL = "/arcgis/admin/security/roles/getRoles"
response, data = postToServer(serverName, serverPort, resourceURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Unable to check if the permission '" + role + "' exists on the server"
print str(data)
return
else:
rolesJSON = json.loads(data)
roles = rolesJSON['roles']
for roleDict in roles :
if (('rolename' in roleDict) and (codecs.decode(roleDict['rolename'],'utf-8') == role)):
return True
return False
def getResourceTypeAndURL(resourceName,serverName,serverPort,token):
resourceURL = None
resourceType = None
if isItFolder(resourceName,serverName,serverPort,token):
resourceURL = "/arcgis/admin/services/"+resourceName+"/permissions"
resourceType = 'folder'
else:
# Check if the resource is a service - it is possible to have the same name for service and folder
# and if a service and a folder have same name, we apply the same permissions on both.
serviceType = getServiceType(resourceName,serverName,serverPort,token)
if serviceType is not None:
resourceURL = "/arcgis/admin/services/"+resourceName+"."+serviceType+"/permissions"
resourceType = 'service'
return [resourceType,resourceURL]
# Helper function that checks to see if the authentication mode is token based
def isTokenBasedAuth(serverName, serverPort, token):
securityConfigURL = "/arcgis/admin/security/config/"
params = urllib.urlencode({'token':token,'f':'json'})
response, data = postToServer(serverName, serverPort, securityConfigURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Unable to determine if the server has token-based authentication or not."
print str(data)
return
# Extract the security store type
securityConfig = json.loads(data)
if (str(securityConfig['authenticationMode']) != "ARCGIS_TOKEN"):
return False
return True
# A function that will post HTTP POST request to the server
def postToServer(serverName, serverPort, url, params):
httpConn = httplib.HTTPConnection(serverName, serverPort)
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# URL encode the resource URL
url = urllib.quote(url.encode('utf-8'))
# Build the connection to add the roles to the server
httpConn.request("POST", url, params, headers)
response = httpConn.getresponse()
data = response.read()
httpConn.close()
return (response, data)
# A function that checks that the JSON response received from the server does not contain an error
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
return False
else:
return True
def getToken(username, password, serverName, serverPort):
tokenURL = "/arcgis/admin/generateToken"
params = urllib.urlencode({'username': username, 'password': password,'client': 'requestip', 'f': 'json'})
response, data = postToServer(serverName, serverPort, tokenURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Error while fetching tokens from admin URL. Please check if the server is running and ensure that the username/password provided are correct"
print str(data)
return ""
else:
# Extract the token from it
token = json.loads(data)
return token['token']
# Checks if the given resource is a folder or not
def isItFolder(resourceName,serverName,serverPort,token):
params = urllib.urlencode({'token':token,'f': 'json'})
folderURL = "/arcgis/admin/services"
response, data = postToServer(serverName, serverPort, folderURL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Error while fetching folders from the server."
print str(data)
return
else:
# Check if the resource is a folder
rootJSON = json.loads(data)
folders = rootJSON['folders']
for folder in folders:
if codecs.decode(folder,'utf-8') == resourceName :
return True
return False
# Checks if the resource is a service; if it is a service it returns the service type; otherwise, it returns None
def getServiceType(resourceName,serverName,serverPort,token):
params = urllib.urlencode({'token':token,'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
folderSeparator = resourceName.find("/")
if folderSeparator == -1 :
# This service is probably present at the root folder
URL = "/arcgis/admin/services/"
serviceName = resourceName
else:
URL = "/arcgis/admin/services/"+resourceName[0:folderSeparator]
serviceName = resourceName[folderSeparator+1:]
response, data = postToServer(serverName, serverPort, URL, params)
if (response.status != 200 or not assertJsonSuccess(data)):
print "Error while fetching the service type from the server."
print str(data)
return
else:
rootJSON = json.loads(data)
services = rootJSON['services']
for service in services:
if codecs.decode(service['serviceName'],'utf-8') == serviceName :
return service['type']
return None
if __name__ == "__main__" :
sys.exit(main(sys.argv[1:]))