Skip To Content

Example: Add members to the portal

In this topic

This example takes an input text file with information about users and adds them to your portal in bulk. Define and grant the role for each user in your portal.

Enter the following required information when running the script:

  • Path to the text file containing the user information, for example, /home/admin/documents/users.txt.
  • Type of users you want to add to the portal, for example, built-in or enterprise. To learn more about user types, see Managing access to your portal.
  • Fully-qualified domain name of the machine hosting your portal, for example, myportal.acme.com. The script accesses your portal over HTTPS on port 7443, bypassing the ArcGIS Web Adaptor. In this manner, the script does not need to handle web tier authentication if your portal is configured to use it.
  • User name and password of an account that has administrative privileges to the portal. If you're adding built-in accounts, provide the credentials of any member of the portal with administrative privileges. If you're adding enterprise accounts, use the initial administrator account created after installing Portal for ArcGIS.
Note:

Demonstrating how to make Python scripts handle web tier authentication is beyond the scope of this example.

Registering enterprise accounts

When registering enterprise accounts, the format for each entry in the text file is as follows:

<login>|<email address>|<name>|<role>|<description>|<Idp UserName>

  • login—The enterprise login to register.

    • If using Active Directory, this login is in the form of sAMAccountName@DOMAIN. The domain name must be in all capital letters.
    • If using LDAP, the login matches the value of the userNameAttribute you specified when configuring the identity store.
    • If using SAML-based enterprise logins, the login value specified matches the NameID attribute in the SAML identity provider.
  • email address—The email associated with the login and matches the value in the identity store. If the user account does not have an email address, provide a false or generic value.

  • name—The alias for the login used in your ArcGIS organization. Most identity stores use the user's full name as the default alias. When the user connects to the portal website, this name appears at the top of the website.

  • role—This is the role the enterprise login will have in the ArcGIS organization. Valid role values are user, publisher, admin, or <custom_role_name>, where <custom_role_name> is the name of the custom role (for example, hostedservicepublisher).

    Legacy:

    In Portal for ArcGIS 10.3 and earlier versions, the accepted values for non-custom roles were org_user, org_publisher, and org_admin. At 10.3.1, these values have been deprecated and replaced with the values listed above. You can continue to use the legacy values at 10.3.1, but note that the values may not be accepted in a future release.

  • description—Optionally, include text to describe the account. This value does not correspond to any attribute in the identity store. Descriptions cannot exceed 250 characters.

  • Idp UserName—Optionally, specify the user name of the enterprise account in the identity provider. If this value is not provided, the value specified for the login parameter is used instead.

You're required to provide a value for the login, email address, name, and role. The description and Idp UserName are optional. For each account listed in the file, verify the values you entered for the login, email address, and name exactly match the values in your identity store. The portal will not connect to your identity store to validate these values.

The following is an example of an entry to register an Active Directory enterprise account for login jcho111, with an email address of jcho@domain.com and a full name of Jon Cho. The login is placed in the user role (user) and is described as a user in department b.

jcho111@DOMAIN|jcho@domain.com|Jon Cho|user|department b

The following is an example of an entry to register an enterprise account from a SAML identity provider. The user's login is rsmith@domain.com, with an email address of rsmith@domain.com and a full name of Robert Smith. The login is placed in the publisher role (publisher) with an Idp UserName of rsmith@domain.com.

rsmith@domain.com|rsmith@domain.com|Robert Smith|publisher||rsmith@domain.com

The following is an example of an entry to register an LDAP enterprise account for login sjames4513, with an email address of sjames@domain.com and a full name of Sara James. The login is placed in the user role (admin) and a description is provided.

sjames4513@DOMAIN|sjames@domain.com|Sara James|admin|Department Lead and GIS Manager

The following is an example of an entry to register an enterprise account for login srajhandas, with an email address of srajhandas@domain.com and a full name of Satish Rajhandas. The login is placed in the user role (user).

srajhandas@DOMAIN|srajhandas@domain.com|Satish Rajhandas|user

The following is an example of an entry to register an enterprise account from a SAML identity provider. The user's login is djohnson308, with an email address of djohnson@domain.com and a full name of Daisha Johnson. The login is placed in the user role (user), a description is provided, and the Idp UserName is defined as djohnson@domain.com.

djohnson308@DOMAIN|djohnson@domain.com|Daisha Johnson|user|Account Specialist|djohnson@domain.com

Adding built-in portal accounts

When adding built-in portal accounts, the format for each entry in the text file is as follows:

<username>|<password>|<email address>|<name>|<role>|<description>

  • username—The user name used for the built-in account. User names must be unique; no two members can have the same user name.
  • password—The password assigned to the account. Users can use this password the first time they sign in to the portal, then they can change their password by editing their profile.
  • email address—Provide an email address for this account. This parameter is required; therefore, you must provide a value for the email address even if it is not a valid address.
  • name—The alias for the account used in your ArcGIS organization. When the user connects to the portal website, this name appears at the top of the portal website.
  • role—The role the account has in the ArcGIS organization. Valid role values are user, publisher, admin, or org_<custom_role_name>, where <custom_role_name> is the name of the custom role (for example, org_hostedservicepublisher).
  • description—Optionally, include text to describe the account. Descriptions cannot exceed 250 characters.

The following is an example of an entry that adds a built-in portal account with the user name pub1 for Barbara Williams and an email account of bwilliams@domain.com. It also adds pub1 to the publisher role:

pub1|changepasswordlater|bwilliams@domain.com|Barbara Williams|publisher

The following is an example of an entry that adds a built-in portal account with the user name jcho for Jon Cho and an email account of jcho@domain.com. It also adds jcho to the administrator role and describes it as the GIS manager:

jcho|changepasswordlater|jcho@domain.com|Jon Cho|admin|GIS Manager

#!/usr/bin/env python
# Requires Python 2.7+

# Demonstrates how to add users to Portal for ArcGIS in bulk

# For Http calls
import httplib, urllib2, urllib, json
# For system tools
import sys, os
# For reading passwords without echoing
import getpass
# Other utilities
import Queue

# Defines the entry point into the script
def main(argv):

    print "This script adds users in bulk into a portal. \n"

    #Get parameters
    parameters = getParametersFromUser ()

    portalURL = parameters['portalURL']
    provider = parameters['provider']
    userName = parameters['userName']
    password = parameters['password']
    inUserFile = parameters['inUserFile']


    #Get user data from file
    usersData = getUserDataFromFile(inUserFile,provider)

    #Create users
    createUsers (userName,password, portalURL,provider, usersData)

    raw_input('Press ENTER to close the script.')

    return


# This function loads all the user data in the input text file into a Python Queue.
# This usersQueue can be later passed to the createUsers function
def getUserDataFromFile(inUserFile,provider):


    usersQ = Queue.Queue()
    keyParams = ['username', 'password', 'email', 'fullname','role','description']

    inFileHandle = open(inUserFile, 'r')
    userCount = 0
    print '...Processing input users file at: ' + inUserFile
    entryCount = 1;
    for line in inFileHandle.readlines():
        userParams = line.split('|')
        userParamDict = {}
        if provider=="webadaptor":
            if len(userParams) == 5:
                for i in range (0,5):
                    userParamDict[keyParams[0]] = userParams[0]  # login
                    userParamDict[keyParams[1]] = ""
                    userParamDict[keyParams[2]] = userParams[1]  # email address
                    userParamDict[keyParams[3]] = userParams[2]  # name
                    userParamDict[keyParams[4]] = userParams[3]  # role
                    userParamDict[keyParams[5]] = userParams[4].replace('\n','')  # description
                usersQ.put (userParamDict)
                userCount = userCount + 1
            else:
                print ' The format for entry %s is invalid.  The format for enterprise accounts should be <login>|<email address>|<name>|<role>|<description>. \n '% (entryCount)

                raise SystemExit( 'When registering enterprise accounts, the format for each entry is as follows: <login>|<email address>|<name>|<role>|<description>')
        elif provider=="arcgis":
            if len(userParams) == 6:
                for i in range (0,6):
                    userParamDict[keyParams[0]] = userParams[0]  # account
                    userParamDict[keyParams[1]] = userParams[1]  # password
                    userParamDict[keyParams[2]] = userParams[2]  # email address
                    userParamDict[keyParams[3]] = userParams[3]  # name
                    userParamDict[keyParams[4]] = userParams[4]  # role
                    userParamDict[keyParams[5]] = userParams[5].replace('\n','')  # description
                usersQ.put (userParamDict)
                userCount = userCount + 1
            else:
                print ' The format for entry %s is invalid.  The format for built-in portal accounts should be <account>|<password>|<email address>|<name>|<role>|<description>.  \n '% (entryCount)
                raise SystemExit( 'When registering built-in portal accounts, the format for each entry is as follows: <account>|<password>|<email address>|<name>|<role>|<description>')
        else:
            print '   The provider is incorrect. Script ended. \n'
            raise SystemExit( 'The value for the user type is invalid. ')
        entryCount = entryCount +1
        if not ((userParamDict[keyParams[4]].lower()== "user") or (userParamDict[keyParams[4]].lower()=="publisher") or (userParamDict[keyParams[4]].lower()== "admin")):
            raise SystemExit( 'The value for the user role %s in users text file is invalid.  Accepted values are user or publisher or admin. ' % (userParamDict[keyParams[4]]))
    inFileHandle.close()
    # Create users and report results
    print '...Total members to be added: ' + str(userCount)

    return usersQ


# This function connects to the portal and adds members to it from a collection
def createUsers(username,password, portalUrl, provider,userParamsQ):

    print '...Connecting to ' + portalUrl
    token = generateToken(username,password, portalUrl)
    print '...Adding users '
    usersLeftInQueue = True
    while usersLeftInQueue:
        try:
            userDict = userParamsQ.get(False)
            userDict['f'] = 'json'
            userDict['token'] = token
            userDict['provider'] = provider
            params = urllib.urlencode(userDict)

            request = urllib2.Request(portalUrl + '/portaladmin/security/users/createUser?',params, { 'Referer' : portalUrl })

            # POST the create request
            response = urllib2.urlopen(request).read()
            responseJSON = json.loads(response)

            # Log results
            if responseJSON.has_key('error'):
                errDict = responseJSON['error']
                if int(errDict['code'])==498:
                    message = 'Token Expired. Getting new token... Username: ' + userDict['username'] + ' will be added later'
                    token = generateToken(username,password, portalUrl)
                    userParamsQ.put(userDict)
                else:
                    message =  'Error Code: %s \n Message: %s' % (errDict['code'],
                    errDict['message'])
                print '\n' + message
            else:
                # Success
                if responseJSON.has_key('status'):
                    resultStatus = responseJSON['status']
                    print '\n' + 'User: %s account created' % (userDict['username'])

                    print 'User: %s account created' % (userDict['username'])
        except Queue.Empty:
              usersLeftInQueue = False

# This function gets a token from the portal
def generateToken(username, password, portalUrl):
    '''Retrieves a token to be used with API requests.'''
    parameters = urllib.urlencode({'username' : username,
                                   'password' : password,
                                   'client' : 'referer',
                                   'referer': portalUrl,
                                   'expiration': 60,
                                   'f' : 'json'})
    try:
        response = urllib.urlopen(portalUrl + '/sharing/rest/generateToken?',
                              parameters).read()
    except Exception as e:
        raise SystemExit( 'Unable to open the url %s/sharing/rest/generateToken' % (portalUrl))
    responseJSON =  json.loads(response.strip(' \t\n\r'))
    # Log results
    if responseJSON.has_key('error'):
        errDict = responseJSON['error']
        if int(errDict['code'])==498:
            message = 'Token Expired. Getting new token... '
            token = generateToken(username,password, portalUrl)
        else:
            message =  'Error Code: %s \n Message: %s' % (errDict['code'],
            errDict['message'])
            raise SystemExit(message)
    token = responseJSON.get('token')
    return token

# This function gets gets parameters from the user in interactive mode
def getParametersFromUser():

    parameters = {}
    # Get Location of users file
    inUserFile = raw_input ("Enter path to users text file: ")
    if not os.path.exists(inUserFile):
        print '   File does not exist. Script ended. \n'
        raise SystemExit( 'Input file: %s does not exist' % (inUserFile))
    parameters['inUserFile'] = inUserFile

    # Enteprise logins or built-in accounts?
    userInput = raw_input ("What type of users do you want to add to the portal?  Accepted values are built-in or enterprise: ")
    if userInput.lower()=="built-in":
        parameters['provider'] = 'arcgis'
        print '   Built-in accounts will be added to the portal. \n'
    elif userInput.lower()=="enterprise":
        parameters['provider'] = 'webadaptor'
        print '   Enterprise accounts will be added to the portal. \n'
    else:
        print '   The type of users is incorrect. Script ended. \n'
        raise SystemExit( 'The value entered for the user type %s is invalid.  Accepted values are built-in or enterprise. ' % (userInput))

    # Get Portal URL
    hostname = raw_input("Enter the fully qualified portal hostname (for example myportal.acme.com): ")
    parameters['portalURL'] = 'https://' + hostname + ':7443/arcgis'
    print '   Users will be added to portal at: ' + parameters['portalURL'] + '\n'

    # Get a username and password with portal administrative privileges
    parameters['userName'] = raw_input("Enter a built-in user name with portal administrative privileges:")

    parameters['password'] = raw_input("Enter password: ")
    print '\n'

    return  parameters

# Script start
if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))