This script reads a list of permissions from a pipe-delimited text file you provide and applies the permissions to your services. You provide the list in this format:
#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—The name of a service running on ArcGIS Server. The use of / means the service is in a folder.
- resourceType—Used only for clarification when a folder and a service have the same name. Values are service or folder.
- permissions—A comma-separated list of ArcGIS Server roles that should receive permissions to the service. Two special roles are available: allLoggedInUsers gives permissions to anyone who has logged in with a user name from ArcGIS Server's user store, and the role public allows access to everyone whether logged in or not. These two roles only work when the server is configured with token-based authentication.
Any services not mentioned in the text file are left open for public access.
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:]))