12 changed files with 1611 additions and 1611 deletions
@ -1,111 +1,111 @@ |
|||
Contributor Agreement |
|||
|
|||
|
|||
|
|||
Version 1.1 |
|||
|
|||
|
|||
|
|||
Contributions to this software are accepted only when they are |
|||
|
|||
properly accompanied by a Contributor Agreement. The Contributor |
|||
|
|||
Agreement for this software is the Developer's Certificate of Origin |
|||
|
|||
1.1 (DCO) as provided with and required for accepting contributions |
|||
|
|||
to the Linux kernel. |
|||
|
|||
|
|||
|
|||
In each contribution proposed to be included in this software, the |
|||
|
|||
developer must include a "sign-off" that denotes consent to the |
|||
|
|||
terms of the Developer's Certificate of Origin. The sign-off is |
|||
|
|||
a line of text in the description that accompanies the change, |
|||
|
|||
certifying that you have the right to provide the contribution |
|||
|
|||
to be included. For changes provided in source code control (for |
|||
|
|||
example, via a Git pull request) the sign-off must be included in |
|||
|
|||
the commit message in source code control. For changes provided |
|||
|
|||
in email or issue tracking, the sign-off must be included in the |
|||
|
|||
email or the issue, and the sign-off will be incorporated into the |
|||
|
|||
permanent commit message if the contribution is accepted into the |
|||
|
|||
official source code. |
|||
|
|||
|
|||
|
|||
If you can certify the below: |
|||
|
|||
|
|||
|
|||
Developer's Certificate of Origin 1.1 |
|||
|
|||
|
|||
|
|||
By making a contribution to this project, I certify that: |
|||
|
|||
|
|||
|
|||
(a) The contribution was created in whole or in part by me and I |
|||
|
|||
have the right to submit it under the open source license |
|||
|
|||
indicated in the file; or |
|||
|
|||
|
|||
|
|||
(b) The contribution is based upon previous work that, to the best |
|||
|
|||
of my knowledge, is covered under an appropriate open source |
|||
|
|||
license and I have the right under that license to submit that |
|||
|
|||
work with modifications, whether created in whole or in part |
|||
|
|||
by me, under the same open source license (unless I am |
|||
|
|||
permitted to submit under a different license), as indicated |
|||
|
|||
in the file; or |
|||
|
|||
|
|||
|
|||
(c) The contribution was provided directly to me by some other |
|||
|
|||
person who certified (a), (b) or (c) and I have not modified |
|||
|
|||
it. |
|||
|
|||
|
|||
|
|||
(d) I understand and agree that this project and the contribution |
|||
|
|||
are public and that a record of the contribution (including all |
|||
|
|||
personal information I submit with it, including my sign-off) is |
|||
|
|||
maintained indefinitely and may be redistributed consistent with |
|||
|
|||
this project or the open source license(s) involved. |
|||
|
|||
|
|||
|
|||
then you just add a line saying |
|||
|
|||
|
|||
|
|||
Signed-off-by: Random J Developer <random@developer.example.org> |
|||
|
|||
|
|||
|
|||
Contributor Agreement |
|||
|
|||
|
|||
|
|||
Version 1.1 |
|||
|
|||
|
|||
|
|||
Contributions to this software are accepted only when they are |
|||
|
|||
properly accompanied by a Contributor Agreement. The Contributor |
|||
|
|||
Agreement for this software is the Developer's Certificate of Origin |
|||
|
|||
1.1 (DCO) as provided with and required for accepting contributions |
|||
|
|||
to the Linux kernel. |
|||
|
|||
|
|||
|
|||
In each contribution proposed to be included in this software, the |
|||
|
|||
developer must include a "sign-off" that denotes consent to the |
|||
|
|||
terms of the Developer's Certificate of Origin. The sign-off is |
|||
|
|||
a line of text in the description that accompanies the change, |
|||
|
|||
certifying that you have the right to provide the contribution |
|||
|
|||
to be included. For changes provided in source code control (for |
|||
|
|||
example, via a Git pull request) the sign-off must be included in |
|||
|
|||
the commit message in source code control. For changes provided |
|||
|
|||
in email or issue tracking, the sign-off must be included in the |
|||
|
|||
email or the issue, and the sign-off will be incorporated into the |
|||
|
|||
permanent commit message if the contribution is accepted into the |
|||
|
|||
official source code. |
|||
|
|||
|
|||
|
|||
If you can certify the below: |
|||
|
|||
|
|||
|
|||
Developer's Certificate of Origin 1.1 |
|||
|
|||
|
|||
|
|||
By making a contribution to this project, I certify that: |
|||
|
|||
|
|||
|
|||
(a) The contribution was created in whole or in part by me and I |
|||
|
|||
have the right to submit it under the open source license |
|||
|
|||
indicated in the file; or |
|||
|
|||
|
|||
|
|||
(b) The contribution is based upon previous work that, to the best |
|||
|
|||
of my knowledge, is covered under an appropriate open source |
|||
|
|||
license and I have the right under that license to submit that |
|||
|
|||
work with modifications, whether created in whole or in part |
|||
|
|||
by me, under the same open source license (unless I am |
|||
|
|||
permitted to submit under a different license), as indicated |
|||
|
|||
in the file; or |
|||
|
|||
|
|||
|
|||
(c) The contribution was provided directly to me by some other |
|||
|
|||
person who certified (a), (b) or (c) and I have not modified |
|||
|
|||
it. |
|||
|
|||
|
|||
|
|||
(d) I understand and agree that this project and the contribution |
|||
|
|||
are public and that a record of the contribution (including all |
|||
|
|||
personal information I submit with it, including my sign-off) is |
|||
|
|||
maintained indefinitely and may be redistributed consistent with |
|||
|
|||
this project or the open source license(s) involved. |
|||
|
|||
|
|||
|
|||
then you just add a line saying |
|||
|
|||
|
|||
|
|||
Signed-off-by: Random J Developer <random@developer.example.org> |
|||
|
|||
|
|||
|
|||
using your real name (sorry, no pseudonyms or anonymous contributions.) |
|||
@ -1,59 +1,59 @@ |
|||
**pyviyatools Install Intructions** |
|||
|
|||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. |
|||
|
|||
**INSTALL** |
|||
|
|||
The tools are a package of files and should be downloaded as such. The individual files are not useable without the package. |
|||
|
|||
The tools should be installed on the same machine that hosts the Viya command-line interfaces(CLI). The following command will install a copy of the tools in a sub-directory(pyviyatools) of the current directory. |
|||
|
|||
*git clone https://github.com/sassoftware/pyviyatools.git* |
|||
|
|||
**Authenticate** |
|||
|
|||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. This process is documented in the SAS Viya Administration guide here. |
|||
|
|||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
|||
|
|||
|
|||
If your environment is enabled for Transport Layer Security (TLS), you must set the SSL_CERT_FILE environment variable to the path location of the trustedcerts.pem file (if using the SAS default truststore) |
|||
or the path location of your site-signed certificate (if using an internal truststore). |
|||
|
|||
In addition you may need to set REQUESTS_CA_BUNDLE to the certificate location so that the requests library can find the certificates. |
|||
|
|||
The tool will automatically use the default profile. |
|||
|
|||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
|||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
|||
3. After you create the profile there are two options to authenticate |
|||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
|||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
|||
|
|||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
|||
|
|||
1. Create a named profile *sas-admin --profile newprofile profile init* |
|||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
|||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
|||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
|||
|
|||
4. To revert to using the default variable reset the environment variable |
|||
|
|||
* LINUX: *unset SAS_CLI_PROFILE* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=* |
|||
|
|||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
|||
|
|||
|
|||
**TEST** |
|||
|
|||
1. Execute a test call. Change directory to your install directory and run: |
|||
|
|||
*callrestapi.py -e /folders/folders -m get* |
|||
|
|||
The call should return the JSON for the folders in the viya deployment. Be patient it might take a few seconds the first time. |
|||
|
|||
2. To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
|||
|
|||
*showsetup.py* |
|||
**pyviyatools Install Intructions** |
|||
|
|||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. |
|||
|
|||
**INSTALL** |
|||
|
|||
The tools are a package of files and should be downloaded as such. The individual files are not useable without the package. |
|||
|
|||
The tools should be installed on the same machine that hosts the Viya command-line interfaces(CLI). The following command will install a copy of the tools in a sub-directory(pyviyatools) of the current directory. |
|||
|
|||
*git clone https://github.com/sassoftware/pyviyatools.git* |
|||
|
|||
**Authenticate** |
|||
|
|||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. This process is documented in the SAS Viya Administration guide here. |
|||
|
|||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
|||
|
|||
|
|||
If your environment is enabled for Transport Layer Security (TLS), you must set the SSL_CERT_FILE environment variable to the path location of the trustedcerts.pem file (if using the SAS default truststore) |
|||
or the path location of your site-signed certificate (if using an internal truststore). |
|||
|
|||
In addition you may need to set REQUESTS_CA_BUNDLE to the certificate location so that the requests library can find the certificates. |
|||
|
|||
The tool will automatically use the default profile. |
|||
|
|||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
|||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
|||
3. After you create the profile there are two options to authenticate |
|||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
|||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
|||
|
|||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
|||
|
|||
1. Create a named profile *sas-admin --profile newprofile profile init* |
|||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
|||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
|||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
|||
|
|||
4. To revert to using the default variable reset the environment variable |
|||
|
|||
* LINUX: *unset SAS_CLI_PROFILE* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=* |
|||
|
|||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
|||
|
|||
|
|||
**TEST** |
|||
|
|||
1. Execute a test call. Change directory to your install directory and run: |
|||
|
|||
*callrestapi.py -e /folders/folders -m get* |
|||
|
|||
The call should return the JSON for the folders in the viya deployment. Be patient it might take a few seconds the first time. |
|||
|
|||
2. To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
|||
|
|||
*showsetup.py* |
|||
|
|||
@ -1,284 +1,284 @@ |
|||
# Python Tools for SAS Viya |
|||
|
|||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. The tools are designed to be used in conjunction with the sas-admin command line interfaces(CLI). |
|||
|
|||
## Getting Started |
|||
|
|||
### Documentation |
|||
|
|||
You can find the SAS Open API's documented: https://developer.sas.com/apis/rest/ |
|||
|
|||
Some other useful links |
|||
|
|||
* https://developer.sas.com/apis/rest/#filters |
|||
* https://developer.sas.com/apis/rest/#pagination |
|||
* https://developer.sas.com/apis/rest/#sorting |
|||
|
|||
### Prerequisites |
|||
|
|||
The tools requires either python 2 or python 3. |
|||
|
|||
The following python libraries are used: |
|||
|
|||
* requests http://docs.python-requests.org/en/master/ |
|||
* sys |
|||
* json |
|||
* os |
|||
* netrc |
|||
* subprocess |
|||
* platform |
|||
* argeparse |
|||
|
|||
|
|||
### Installing |
|||
|
|||
Please use the installation intructions in the file INSTALL.md [INSTALL.md](INSTALL.md) |
|||
|
|||
### Running |
|||
|
|||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. |
|||
|
|||
This process is documented in the SAS Viya Administration guide here. |
|||
|
|||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
|||
|
|||
#### Creating a Profile and Logging on |
|||
|
|||
The tool will automatically use the default profile. |
|||
|
|||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
|||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
|||
3. After you create the profile there are two options to authenticate |
|||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
|||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
|||
|
|||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
|||
|
|||
1. Create a named profile *sas-admin --profile newprofile profile init* |
|||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
|||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
|||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
|||
|
|||
4. When the SAS_CLI_PROFILE is set the tool will use the profile stored in the variable |
|||
5. To revert to using the default variable reset the environment variable |
|||
|
|||
* LINUX: *unset SAS_CLI_PROFILE* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=* |
|||
|
|||
|
|||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
|||
|
|||
python *\<pathtotool\>\<toolname.py\>* -h |
|||
|
|||
|
|||
**Available Tools** |
|||
|
|||
**callrestapi** |
|||
|
|||
callrestapi is a general tool, and the building block for all the other tools. |
|||
|
|||
callrestapi will call the Viya REST API and return json or optionally a simplified output. It can call any viya REST method. (Like a curl command). |
|||
|
|||
*usage: callrestapi.py [-h] -e ENDPOINT -m {get,put,post,delete} [-i INPUTFILE] [-a ACCEPTTYPE] [-c CONTENTTYPE] [-o {csv,json,simple}]* |
|||
|
|||
You must pass a method and endpoint. You can optionally pass json, content type headers or the -t flag to change output from json to basic text. |
|||
|
|||
**List of some of the Additional Tools Available** |
|||
|
|||
Additional tools provide more complex functionality by combining multiple calls to the callrestapi function, and post-processing the outpuit that is returned. |
|||
|
|||
* **getfolderid** returns the id of the folder based on the full folder path |
|||
* **deletefolder** deletes a folder based on the full folder path |
|||
* **deletefolderandcontent** deletes a folder and any reports that are stored in the folder |
|||
* **movecontent** moves the content from a source to a target folder |
|||
* **getconfigurationproperties** lists the name/value pairs of a configuration |
|||
* **testfolderaccess** tests if a user or group has access to a folder |
|||
* **createbinarybackup.py** creates a binary backup job |
|||
* **createdomain.py** creates an authentication domain |
|||
* **listrules.py** list authorization rules subset on a principal and/or a uri |
|||
* **loginviauthinfo.py** use an authinfo file to authenticate to the CLI |
|||
* **updateprefences.py** update preferences for a user or group of users |
|||
* **updatedomain.py** Load a set of userids and passwords to a Viya domain from a csv file |
|||
* **createfolders.py** Create a set of Viya folders from a csv file |
|||
* **explainaccess.py** Explains access for a folder, object or service endpoint |
|||
|
|||
Check back for additional tools and if you build a tool feel free to contribute it to the collection. |
|||
|
|||
## Examples |
|||
|
|||
The example calls assume you are in the directory where you installed the tools. If you are not you can prepemd the directory to the filename, for example /opt/pyviyatools/callrestapi.py |
|||
If you are using the tool on windows the syntax is: |
|||
|
|||
*python toolname.py* |
|||
|
|||
The following examples are Linux. |
|||
|
|||
\# Login to Viya using default authinfo file ~/.authinfo |
|||
*./loginviauthinfo.py* |
|||
|
|||
\# Login to Viya using an authinfo file |
|||
*./loginviauthinfo.py -f ~/.authinfo_geladm* |
|||
|
|||
\#return all the rest calls that can be made to the folders endpoint |
|||
*./callrestapi.py -e /folders -m get* |
|||
|
|||
\#return the json for all the folders/folders |
|||
*./callrestapi.py -e /folders/folders -m get* |
|||
|
|||
\#return simple text for all the folders/folders |
|||
*./callrestapi.py -e /folders/folders -m get -o simple* |
|||
|
|||
\#rest calls often limit the results returned the text output will tell you returned and total available items |
|||
\#in this call set a limit above the total items to see everything |
|||
*./callrestapi.py -e /folders/folders?limit=500 -m get -o simple* |
|||
|
|||
|
|||
\#return the json for all the identities |
|||
*./callrestapi.py -e /identities/identities -m get* |
|||
|
|||
\#return the json for all the identities output to a file |
|||
*./callrestapi.py -e /identities/identities -m get > identities.json* |
|||
|
|||
\#refresh the identities cache |
|||
*./callrestapi.py -e /identities/userCount -m get* |
|||
*./callrestapi.py -e /identities/cache/refreshes -m post* |
|||
|
|||
\# pass the folder path and return the folder id and uri |
|||
*./getfolderid.py -f /gelcontent* |
|||
|
|||
\# delete a folder based on its path |
|||
*./deletefolder.py -f /gelcontent* |
|||
|
|||
\#return a set of configuration properties |
|||
*./getconfigurationproperties.py -c sas.identities.providers.ldap.user -o simple* |
|||
|
|||
\#create a domain using createdomain |
|||
*./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR ,Sales"* |
|||
|
|||
\#Update an existing domain to add credentials from a csv file |
|||
*./updatedomain.py -d LASRAuth -f /tmp/myusers.csv* |
|||
|
|||
csv file format |
|||
no header row |
|||
column1 is userid |
|||
column2 is password |
|||
column3 is identity |
|||
column4 is identity type (user or group) |
|||
|
|||
For example: |
|||
myuserid,mypass,Sales,group |
|||
acct1,pw1,sasadm,user |
|||
|
|||
\#create a domain using callrestapi. Last part of endpoint is domain name |
|||
*./callrestapi.py -e /credentials/domains/\<newdomain\> -m post -i domain.json* |
|||
|
|||
INPUT JSON must be formatted as the endpoint expects. Example: |
|||
|
|||
{ |
|||
"id": "\<newdomain\>", |
|||
"type": "password" |
|||
} |
|||
|
|||
\#test folder access |
|||
*./root/admin/pyviyatools/testFolderAccess.py -f '/gelcontent' -p Sales -m read -s grant -q* |
|||
|
|||
\#return basic content using accept response type |
|||
*./callrestapi.py -m get -e /identities/users/sasadm -a "application/vnd.sas.identity.basic+json"* |
|||
|
|||
\# Display all sasadministrator rules |
|||
*./listrules.py --p SASadministrators -o simple* |
|||
|
|||
\# Display all rules that contain SASVisual in the URI |
|||
*./listrules.py -u SASVisual -o simple* |
|||
|
|||
\# Create folders from a CSV file |
|||
*./createfolders.py" -f /tmp/newfolders.csv* |
|||
|
|||
FORMAT OF CSV file folder path (parents must exist), description |
|||
/RnD, Folder under root for R&D |
|||
/RnD/reports, reports |
|||
/RnD/analysis, analysis |
|||
/RnD/data plans, data plans |
|||
/temp,My temporary folder |
|||
/temp/mystuff, sub-folder |
|||
|
|||
\# Update the theme for the user sasadm |
|||
*./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb* |
|||
|
|||
|
|||
\#Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
|||
*./explainaccess.py -f /folderA/folderB* |
|||
|
|||
\#As above but for a specific user named Heather |
|||
*./explainaccess.py -f /folderA/folderB -n Heather -t user* |
|||
|
|||
\#As above with a header row |
|||
*./explainaccess.py -f /folderA/folderB --header* |
|||
|
|||
\#As above with a header row and the folder path, which is useful if you concatenate sets of results in one file |
|||
*./explainaccess.py -f /folderA/folderB -p --header* |
|||
|
|||
\#As above showing only rows which include a direct grant or prohibit |
|||
*./explainaccess.py -f /folderA/folderB --direct_only* |
|||
|
|||
\#Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. By default they are not shown for URIs. |
|||
*./explainaccess.py -u /SASEnvironmentManager/dashboard* |
|||
|
|||
\#As above but including a header row and the create permission, which is relevant for services but not for folders and other objects |
|||
*./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create* |
|||
|
|||
\#Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, since none of add, remove or create are applicable to a report. |
|||
*./explainaccess.py -u /reports/reports/*folder_id *--header -l read update delete secure* |
|||
|
|||
\#Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
|||
*./explainaccess.py -u /folders/folders/*folder_id *--header -p -c true* |
|||
|
|||
**Troubleshooting** |
|||
|
|||
The most common problem is an expired access token. You may see a message like: |
|||
|
|||
{"errorCode":0,"message":"Cannot convert access token to JSON","details":["traceId: 6bca23b2b3a2cfda","path: /folders/folders"],"remediation":null,"links":[ ],"version":2,"httpStatusCode":401} |
|||
|
|||
To fix the problem generate a new access token /opt/sas/viya/home/bin/sas-admin auth login |
|||
|
|||
To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
|||
|
|||
*python showsetup.py* |
|||
|
|||
If you get this error : Login failed. Error with security certificate. |
|||
|
|||
Set the environment variable for the SSL certificate file. For example: |
|||
export SSL_CERT_FILE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
|||
|
|||
|
|||
If you get this error: |
|||
Raise SSLError(e, request=request) |
|||
requests.exceptions.SSLError: HTTPSConnectionPool(host='intviya01.race.sas.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),)) |
|||
|
|||
Set the environment variable for the SSL certificate file. For example: |
|||
export REQUESTS_CA_BUNDLE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
|||
|
|||
|
|||
## Developing with the existing functions |
|||
|
|||
The file sharedfunctions.py contains a set of generic functions that make it easy to build additional tools. |
|||
|
|||
*callrestapi* is the main function, called by many other programs and by the callrestapi program to make the REST calls. It accepts as parameters: |
|||
|
|||
* reqval: the request value which is the rest endpoint for the request |
|||
* reqtype: the type of REST request, get,put, post, delete |
|||
* acceptType: optinal accept type content header |
|||
* contentType: optional content type content header |
|||
* data: optionally a python dictionary created from the json for the rest request |
|||
* stoponerror: whether the function will stop all further processing if an error occurs (default 0 to not stop) |
|||
|
|||
|
|||
## Contributing |
|||
|
|||
We welcome your contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to submit contributions to this project. |
|||
|
|||
## License |
|||
|
|||
This project is licensed under the [Apache 2.0 License](LICENSE). |
|||
|
|||
# Python Tools for SAS Viya |
|||
|
|||
The pyviyatools are a set of command-line tools that call the SAS Viya REST API's from python. The tools can be used to make direct calls to any rest-endpoint (like a CURL command) or to build additional tools that make multiple rest calls to provide more complex functionality. The tools are designed to be used in conjunction with the sas-admin command line interfaces(CLI). |
|||
|
|||
## Getting Started |
|||
|
|||
### Documentation |
|||
|
|||
You can find the SAS Open API's documented: https://developer.sas.com/apis/rest/ |
|||
|
|||
Some other useful links |
|||
|
|||
* https://developer.sas.com/apis/rest/#filters |
|||
* https://developer.sas.com/apis/rest/#pagination |
|||
* https://developer.sas.com/apis/rest/#sorting |
|||
|
|||
### Prerequisites |
|||
|
|||
The tools requires either python 2 or python 3. |
|||
|
|||
The following python libraries are used: |
|||
|
|||
* requests http://docs.python-requests.org/en/master/ |
|||
* sys |
|||
* json |
|||
* os |
|||
* netrc |
|||
* subprocess |
|||
* platform |
|||
* argeparse |
|||
|
|||
|
|||
### Installing |
|||
|
|||
Please use the installation intructions in the file INSTALL.md [INSTALL.md](INSTALL.md) |
|||
|
|||
### Running |
|||
|
|||
The pyviya tools use the sas-admin auth CLI to authenticate to Viya. To use the tool you must create a profile and authenticate. |
|||
|
|||
This process is documented in the SAS Viya Administration guide here. |
|||
|
|||
http://documentation.sas.com/?cdcId=calcdc&cdcVersion=3.3&docsetId=calcli&docsetTarget=n1e2dehluji7jon1gk69yggc6i28.htm&locale=en |
|||
|
|||
#### Creating a Profile and Logging on |
|||
|
|||
The tool will automatically use the default profile. |
|||
|
|||
1. To create a profile as a SAS Administrator logon to the machine that contains the Viya CLI's |
|||
2. Run */opt/sas/viya/home/bin/sas-admin profile init* and when prompter enter the base endpoint of your Viya server for example: http://myviyaserver.blah.com. You may enter your personal preference at the other prompts. |
|||
3. After you create the profile there are two options to authenticate |
|||
* Run */opt/sas/viya/home/bin/sas-admin auth login* to authenticate to Viya enter the userid and password of the SAS Administrator when prompted. |
|||
* Create an .authinfo file in your home directory with your userid and password and use **loginviauthinfo.py** to authenticate with the credentials in the file (you can use different authinfo files with the -f option) |
|||
|
|||
The CLI allows for multiple profiles. To use a profile other than the default profile, for example newprofile |
|||
|
|||
1. Create a named profile *sas-admin --profile newprofile profile init* |
|||
2. Logon with the named profile *sas-admin --profile newprofile auth login* |
|||
3. Set the SAS_CLI_PROFILE environment variable to the name of the profile |
|||
* LINUX: *export SAS_CLI_PROFILE=newprofile* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=newprofile* |
|||
|
|||
4. When the SAS_CLI_PROFILE is set the tool will use the profile stored in the variable |
|||
5. To revert to using the default variable reset the environment variable |
|||
|
|||
* LINUX: *unset SAS_CLI_PROFILE* |
|||
* WINDOWS: *set SAS_CLI_PROFILE=* |
|||
|
|||
|
|||
The tools are self-documenting, for help on any tool call the tool passing -h or --help. |
|||
|
|||
python *\<pathtotool\>\<toolname.py\>* -h |
|||
|
|||
|
|||
**Available Tools** |
|||
|
|||
**callrestapi** |
|||
|
|||
callrestapi is a general tool, and the building block for all the other tools. |
|||
|
|||
callrestapi will call the Viya REST API and return json or optionally a simplified output. It can call any viya REST method. (Like a curl command). |
|||
|
|||
*usage: callrestapi.py [-h] -e ENDPOINT -m {get,put,post,delete} [-i INPUTFILE] [-a ACCEPTTYPE] [-c CONTENTTYPE] [-o {csv,json,simple}]* |
|||
|
|||
You must pass a method and endpoint. You can optionally pass json, content type headers or the -t flag to change output from json to basic text. |
|||
|
|||
**List of some of the Additional Tools Available** |
|||
|
|||
Additional tools provide more complex functionality by combining multiple calls to the callrestapi function, and post-processing the outpuit that is returned. |
|||
|
|||
* **getfolderid** returns the id of the folder based on the full folder path |
|||
* **deletefolder** deletes a folder based on the full folder path |
|||
* **deletefolderandcontent** deletes a folder and any reports that are stored in the folder |
|||
* **movecontent** moves the content from a source to a target folder |
|||
* **getconfigurationproperties** lists the name/value pairs of a configuration |
|||
* **testfolderaccess** tests if a user or group has access to a folder |
|||
* **createbinarybackup.py** creates a binary backup job |
|||
* **createdomain.py** creates an authentication domain |
|||
* **listrules.py** list authorization rules subset on a principal and/or a uri |
|||
* **loginviauthinfo.py** use an authinfo file to authenticate to the CLI |
|||
* **updateprefences.py** update preferences for a user or group of users |
|||
* **updatedomain.py** Load a set of userids and passwords to a Viya domain from a csv file |
|||
* **createfolders.py** Create a set of Viya folders from a csv file |
|||
* **explainaccess.py** Explains access for a folder, object or service endpoint |
|||
|
|||
Check back for additional tools and if you build a tool feel free to contribute it to the collection. |
|||
|
|||
## Examples |
|||
|
|||
The example calls assume you are in the directory where you installed the tools. If you are not you can prepemd the directory to the filename, for example /opt/pyviyatools/callrestapi.py |
|||
If you are using the tool on windows the syntax is: |
|||
|
|||
*python toolname.py* |
|||
|
|||
The following examples are Linux. |
|||
|
|||
\# Login to Viya using default authinfo file ~/.authinfo |
|||
*./loginviauthinfo.py* |
|||
|
|||
\# Login to Viya using an authinfo file |
|||
*./loginviauthinfo.py -f ~/.authinfo_geladm* |
|||
|
|||
\#return all the rest calls that can be made to the folders endpoint |
|||
*./callrestapi.py -e /folders -m get* |
|||
|
|||
\#return the json for all the folders/folders |
|||
*./callrestapi.py -e /folders/folders -m get* |
|||
|
|||
\#return simple text for all the folders/folders |
|||
*./callrestapi.py -e /folders/folders -m get -o simple* |
|||
|
|||
\#rest calls often limit the results returned the text output will tell you returned and total available items |
|||
\#in this call set a limit above the total items to see everything |
|||
*./callrestapi.py -e /folders/folders?limit=500 -m get -o simple* |
|||
|
|||
|
|||
\#return the json for all the identities |
|||
*./callrestapi.py -e /identities/identities -m get* |
|||
|
|||
\#return the json for all the identities output to a file |
|||
*./callrestapi.py -e /identities/identities -m get > identities.json* |
|||
|
|||
\#refresh the identities cache |
|||
*./callrestapi.py -e /identities/userCount -m get* |
|||
*./callrestapi.py -e /identities/cache/refreshes -m post* |
|||
|
|||
\# pass the folder path and return the folder id and uri |
|||
*./getfolderid.py -f /gelcontent* |
|||
|
|||
\# delete a folder based on its path |
|||
*./deletefolder.py -f /gelcontent* |
|||
|
|||
\#return a set of configuration properties |
|||
*./getconfigurationproperties.py -c sas.identities.providers.ldap.user -o simple* |
|||
|
|||
\#create a domain using createdomain |
|||
*./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR ,Sales"* |
|||
|
|||
\#Update an existing domain to add credentials from a csv file |
|||
*./updatedomain.py -d LASRAuth -f /tmp/myusers.csv* |
|||
|
|||
csv file format |
|||
no header row |
|||
column1 is userid |
|||
column2 is password |
|||
column3 is identity |
|||
column4 is identity type (user or group) |
|||
|
|||
For example: |
|||
myuserid,mypass,Sales,group |
|||
acct1,pw1,sasadm,user |
|||
|
|||
\#create a domain using callrestapi. Last part of endpoint is domain name |
|||
*./callrestapi.py -e /credentials/domains/\<newdomain\> -m post -i domain.json* |
|||
|
|||
INPUT JSON must be formatted as the endpoint expects. Example: |
|||
|
|||
{ |
|||
"id": "\<newdomain\>", |
|||
"type": "password" |
|||
} |
|||
|
|||
\#test folder access |
|||
*./root/admin/pyviyatools/testFolderAccess.py -f '/gelcontent' -p Sales -m read -s grant -q* |
|||
|
|||
\#return basic content using accept response type |
|||
*./callrestapi.py -m get -e /identities/users/sasadm -a "application/vnd.sas.identity.basic+json"* |
|||
|
|||
\# Display all sasadministrator rules |
|||
*./listrules.py --p SASadministrators -o simple* |
|||
|
|||
\# Display all rules that contain SASVisual in the URI |
|||
*./listrules.py -u SASVisual -o simple* |
|||
|
|||
\# Create folders from a CSV file |
|||
*./createfolders.py" -f /tmp/newfolders.csv* |
|||
|
|||
FORMAT OF CSV file folder path (parents must exist), description |
|||
/RnD, Folder under root for R&D |
|||
/RnD/reports, reports |
|||
/RnD/analysis, analysis |
|||
/RnD/data plans, data plans |
|||
/temp,My temporary folder |
|||
/temp/mystuff, sub-folder |
|||
|
|||
\# Update the theme for the user sasadm |
|||
*./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb* |
|||
|
|||
|
|||
\#Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
|||
*./explainaccess.py -f /folderA/folderB* |
|||
|
|||
\#As above but for a specific user named Heather |
|||
*./explainaccess.py -f /folderA/folderB -n Heather -t user* |
|||
|
|||
\#As above with a header row |
|||
*./explainaccess.py -f /folderA/folderB --header* |
|||
|
|||
\#As above with a header row and the folder path, which is useful if you concatenate sets of results in one file |
|||
*./explainaccess.py -f /folderA/folderB -p --header* |
|||
|
|||
\#As above showing only rows which include a direct grant or prohibit |
|||
*./explainaccess.py -f /folderA/folderB --direct_only* |
|||
|
|||
\#Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. By default they are not shown for URIs. |
|||
*./explainaccess.py -u /SASEnvironmentManager/dashboard* |
|||
|
|||
\#As above but including a header row and the create permission, which is relevant for services but not for folders and other objects |
|||
*./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create* |
|||
|
|||
\#Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, since none of add, remove or create are applicable to a report. |
|||
*./explainaccess.py -u /reports/reports/*folder_id *--header -l read update delete secure* |
|||
|
|||
\#Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
|||
*./explainaccess.py -u /folders/folders/*folder_id *--header -p -c true* |
|||
|
|||
**Troubleshooting** |
|||
|
|||
The most common problem is an expired access token. You may see a message like: |
|||
|
|||
{"errorCode":0,"message":"Cannot convert access token to JSON","details":["traceId: 6bca23b2b3a2cfda","path: /folders/folders"],"remediation":null,"links":[ ],"version":2,"httpStatusCode":401} |
|||
|
|||
To fix the problem generate a new access token /opt/sas/viya/home/bin/sas-admin auth login |
|||
|
|||
To see the current setup, including python and package versions, environment variable settings, profile information and current user. Run |
|||
|
|||
*python showsetup.py* |
|||
|
|||
If you get this error : Login failed. Error with security certificate. |
|||
|
|||
Set the environment variable for the SSL certificate file. For example: |
|||
export SSL_CERT_FILE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
|||
|
|||
|
|||
If you get this error: |
|||
Raise SSLError(e, request=request) |
|||
requests.exceptions.SSLError: HTTPSConnectionPool(host='intviya01.race.sas.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),)) |
|||
|
|||
Set the environment variable for the SSL certificate file. For example: |
|||
export REQUESTS_CA_BUNDLE=/opt/sas/viya/config/etc/SASSecurityCertificateFramework/cacerts/trustedcerts.pem |
|||
|
|||
|
|||
## Developing with the existing functions |
|||
|
|||
The file sharedfunctions.py contains a set of generic functions that make it easy to build additional tools. |
|||
|
|||
*callrestapi* is the main function, called by many other programs and by the callrestapi program to make the REST calls. It accepts as parameters: |
|||
|
|||
* reqval: the request value which is the rest endpoint for the request |
|||
* reqtype: the type of REST request, get,put, post, delete |
|||
* acceptType: optinal accept type content header |
|||
* contentType: optional content type content header |
|||
* data: optionally a python dictionary created from the json for the rest request |
|||
* stoponerror: whether the function will stop all further processing if an error occurs (default 0 to not stop) |
|||
|
|||
|
|||
## Contributing |
|||
|
|||
We welcome your contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to submit contributions to this project. |
|||
|
|||
## License |
|||
|
|||
This project is licensed under the [Apache 2.0 License](LICENSE). |
|||
|
|||
|
|||
@ -1,93 +1,93 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# createfolders.py |
|||
# October 2018 |
|||
# |
|||
# |
|||
# Change History |
|||
# |
|||
# 30oct2018 Initial development |
|||
# |
|||
# Format of csv file is two columns |
|||
# Column 1 is the full path to the folder |
|||
# Column 2 is a description |
|||
# |
|||
# For example: |
|||
#/RnD, Folder under root for R&D |
|||
#/RnD/reports, reports |
|||
#/RnD/analysis, analysis |
|||
#/RnD/data plans, data plans |
|||
#/temp,My temporary folder |
|||
|
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
import argparse |
|||
import csv |
|||
import os |
|||
from sharedfunctions import callrestapi, getfolderid, file_accessible |
|||
|
|||
# setup command-line arguements |
|||
parser = argparse.ArgumentParser(description="Create folders that are read from a csv file") |
|||
parser.add_argument("-f","--file", help="Full path to csv file containing folders, format of csv: 'folderpath,description ",required='True') |
|||
args = parser.parse_args() |
|||
file=args.file |
|||
|
|||
reqtype="post" |
|||
|
|||
check=file_accessible(file,'r') |
|||
|
|||
# file can be read |
|||
if check: |
|||
|
|||
with open(file, 'rt') as f: |
|||
|
|||
filecontents = csv.reader(f) |
|||
for row in filecontents: |
|||
|
|||
#print(row) |
|||
newfolder=row[0] |
|||
description=row[1] |
|||
|
|||
|
|||
if newfolder[0]!='/': newfolder="/"+newfolder |
|||
|
|||
folder=os.path.basename(os.path.normpath(newfolder)) |
|||
parent_folder=os.path.dirname(newfolder) |
|||
|
|||
data = {} |
|||
data['name'] = folder |
|||
data['description'] = description |
|||
|
|||
|
|||
print ("Creating folder "+newfolder ) |
|||
|
|||
if parent_folder=="/": reqval='/folders/folders' |
|||
else: # parent folder create a child |
|||
|
|||
parentinfo=getfolderid(parent_folder) |
|||
|
|||
if parentinfo != None: |
|||
|
|||
parenturi=parentinfo[1] |
|||
reqval='/folders/folders?parentFolderUri='+parenturi |
|||
|
|||
else: print("Parent folder not found") |
|||
|
|||
myresult=callrestapi(reqval,reqtype,data=data,stoponerror=0) |
|||
else: |
|||
print("ERROR: cannot read "+file) |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# createfolders.py |
|||
# October 2018 |
|||
# |
|||
# |
|||
# Change History |
|||
# |
|||
# 30oct2018 Initial development |
|||
# |
|||
# Format of csv file is two columns |
|||
# Column 1 is the full path to the folder |
|||
# Column 2 is a description |
|||
# |
|||
# For example: |
|||
#/RnD, Folder under root for R&D |
|||
#/RnD/reports, reports |
|||
#/RnD/analysis, analysis |
|||
#/RnD/data plans, data plans |
|||
#/temp,My temporary folder |
|||
|
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
import argparse |
|||
import csv |
|||
import os |
|||
from sharedfunctions import callrestapi, getfolderid, file_accessible |
|||
|
|||
# setup command-line arguements |
|||
parser = argparse.ArgumentParser(description="Create folders that are read from a csv file") |
|||
parser.add_argument("-f","--file", help="Full path to csv file containing folders, format of csv: 'folderpath,description ",required='True') |
|||
args = parser.parse_args() |
|||
file=args.file |
|||
|
|||
reqtype="post" |
|||
|
|||
check=file_accessible(file,'r') |
|||
|
|||
# file can be read |
|||
if check: |
|||
|
|||
with open(file, 'rt') as f: |
|||
|
|||
filecontents = csv.reader(f) |
|||
for row in filecontents: |
|||
|
|||
#print(row) |
|||
newfolder=row[0] |
|||
description=row[1] |
|||
|
|||
|
|||
if newfolder[0]!='/': newfolder="/"+newfolder |
|||
|
|||
folder=os.path.basename(os.path.normpath(newfolder)) |
|||
parent_folder=os.path.dirname(newfolder) |
|||
|
|||
data = {} |
|||
data['name'] = folder |
|||
data['description'] = description |
|||
|
|||
|
|||
print ("Creating folder "+newfolder ) |
|||
|
|||
if parent_folder=="/": reqval='/folders/folders' |
|||
else: # parent folder create a child |
|||
|
|||
parentinfo=getfolderid(parent_folder) |
|||
|
|||
if parentinfo != None: |
|||
|
|||
parenturi=parentinfo[1] |
|||
reqval='/folders/folders?parentFolderUri='+parenturi |
|||
|
|||
else: print("Parent folder not found") |
|||
|
|||
myresult=callrestapi(reqval,reqtype,data=data,stoponerror=0) |
|||
else: |
|||
print("ERROR: cannot read "+file) |
|||
|
|||
@ -1,293 +1,293 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# explainaccess.py |
|||
# November 2018 |
|||
# |
|||
# Usage: |
|||
# explainaccess.py [-f folderpath | -u objectURI] [-n name_of_user_or_group -t user|group] [-p] [--header] [--direct_only] [-l permissions_list] [-c true|false] [-d] |
|||
# |
|||
# Examples: |
|||
# |
|||
# 1. Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
|||
# ./explainaccess.py -f /folderA/folderB |
|||
# |
|||
# 2. As 1. but for a specific user named Heather |
|||
# ./explainaccess.py -f /folderA/folderB -n Heather -t user |
|||
# |
|||
# 3. As 1. with a header row |
|||
# ./explainaccess.py -f /folderA/folderB --header |
|||
# |
|||
# 4. As 1. with a header row and the folder path, which is useful if you concatenate sets of results in one file |
|||
# ./explainaccess.py -f /folderA/folderB -p --header |
|||
# |
|||
# 5. As 1. showing only rows which include a direct grant or prohibit |
|||
# ./explainaccess.py -f /folderA/folderB --direct_only |
|||
# |
|||
# 6. Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. |
|||
# By default they are not shown for URIs. |
|||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard |
|||
# |
|||
# 7. As 6. but including a header row and the create permission, which is relevant for services but not for folders and other objects |
|||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create |
|||
# |
|||
# 8. Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, |
|||
# since none of add, remove or create are applicable to a report. |
|||
# ./explainaccess.py -u /reports/reports/e2e0e601-b5a9-4601-829a-c5137f7441c6 --header -l read update delete secure |
|||
# |
|||
# 9. Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness |
|||
# we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
|||
# ./explainaccess.py -u /folders/folders/9145d26a-2c0d-4523-8835-ad186bb57fa6 --header -p -c true |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
|
|||
clidir='/opt/sas/viya/home/bin/' |
|||
debug=False |
|||
direct_only=False |
|||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
|||
default_permissions=['read','update','delete','secure','add','remove'] |
|||
#direct_permission_suffix=u"\u2666" #Black diamond suit symbol - ok in stdout, seems to cause problems with other tools |
|||
direct_permission_suffix='*' |
|||
|
|||
|
|||
# Import Python modules |
|||
|
|||
import argparse |
|||
import subprocess |
|||
import json |
|||
import sys |
|||
|
|||
from sharedfunctions import getfolderid,callrestapi |
|||
|
|||
# Define exception handler so that we only output trace info from errors when in debug mode |
|||
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook): |
|||
if debug: |
|||
debug_hook(exception_type, exception, traceback) |
|||
else: |
|||
print "%s: %s" % (exception_type.__name__, exception) |
|||
|
|||
sys.excepthook = exception_handler |
|||
|
|||
parser = argparse.ArgumentParser() |
|||
parser.add_argument("-f","--folderpath", help="Path to a Viya folder. You must specify either -f folderpath or -u objectURI.") |
|||
parser.add_argument("-u","--objecturi", help="Object URI. You must specify either -f folderpath or -u objectURI.") |
|||
parser.add_argument("-n","--name", help="Enter the name of the user or group to test.") |
|||
parser.add_argument("-t","--principaltype", help="Enter the type of principal to test: user or group.",choices=['user','group']) |
|||
parser.add_argument("-p","--printpath", action='store_true', help="Print the folder path in each row") |
|||
parser.add_argument("--header", action='store_true', help="Print a header row") |
|||
parser.add_argument("--direct_only", action='store_true', help="Show only explanations which include a direct grant or prohibit") |
|||
parser.add_argument("-l","--permissions_list", nargs="+", help="List of permissions, to include instead of all seven by default", default=default_permissions) |
|||
parser.add_argument("-c","--convey", help="Show conveyed permissions in results. True by default when folder path is specified. False by dfefault if Object URI is specified.",choices=['true','false']) |
|||
parser.add_argument("-d","--debug", action='store_true', help="Debug") |
|||
args = parser.parse_args() |
|||
path_to_folder=args.folderpath |
|||
objecturi=args.objecturi |
|||
name=args.name |
|||
principaltype=args.principaltype |
|||
printpath=args.printpath |
|||
header=args.header |
|||
direct_only=args.direct_only |
|||
permissions=args.permissions_list |
|||
conveyparam=args.convey |
|||
debug=args.debug |
|||
|
|||
if path_to_folder and objecturi: |
|||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI, but not both.') |
|||
if path_to_folder is None and objecturi is None: |
|||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI. You may not specify both.') |
|||
|
|||
if name and principaltype is None: |
|||
raise Exception('If you specify a principal name, you must also specify a principal type which can be user or group.') |
|||
if principaltype and name is None: |
|||
raise Exception('If you specify a principal type, you must also specify a principal name.') |
|||
|
|||
for permission in permissions: |
|||
if permission not in valid_permissions: |
|||
raise Exception(permission+' is not the name of a permission. Valid permissions are: '+' '.join(map(str, valid_permissions))) |
|||
|
|||
# Two ways this program can be used: for a folder, or for a URI. |
|||
if path_to_folder: |
|||
getfolderid_result_json=getfolderid(path_to_folder) |
|||
|
|||
if (debug): |
|||
print(getfolderid_result_json) |
|||
|
|||
|
|||
if getfolderid_result_json[0] is not None: |
|||
folder_uri=getfolderid_result_json[1] |
|||
if (debug): |
|||
print("Id = "+getfolderid_result_json[0]) |
|||
print("URI = "+folder_uri) |
|||
print("Path = "+getfolderid_result_json[2]) |
|||
|
|||
explainuri=folder_uri |
|||
resultpath=path_to_folder |
|||
#Set convey to true, unless user overrode that setting and asked for false |
|||
if(conveyparam is not None and conveyparam.lower()=='false'): |
|||
convey=False |
|||
else: |
|||
convey=True |
|||
|
|||
else: |
|||
explainuri=objecturi |
|||
# This tool explains the permissions of any object. |
|||
# If the object is a folder, we expect the user to supply path_to_folder, and we find its ID |
|||
# If the object is something else, we don't have the path to the object. |
|||
# It might be possible to get the path to the object from it's ID, but I'm not sure if there is a universal way to do that. |
|||
# If the object is a report, you can call e.g. |
|||
# /opt/sas/viya/home/bin/sas-admin --output text reports show-info -id 43de1f98-d7ef-4490-bb46-cc177f995052 |
|||
# And the folder is one of the results passed back. But that call uses the reports plug-in to sas-admin and |
|||
# should not be expected to return the path to other objects. |
|||
# Plus, some objects do not have a path: service endpoints, for example. |
|||
# This is a possible area for future improvement. |
|||
resultpath=objecturi |
|||
#Set convey to false, unless user overrode that setting and asked for true |
|||
if(conveyparam is not None and conveyparam.lower()=='true'): |
|||
convey=True |
|||
else: |
|||
convey=False |
|||
|
|||
|
|||
#Use the /authorization/decision endpoint to ask for an explanation of the rules that are relevant to principals on this URI |
|||
#See Authorization API documentation in swagger at http://swagger.na.sas.com/apis/authorization/v4/apidoc.html#op:createExplanation |
|||
endpoint='/authorization/decision' |
|||
if name and principaltype: |
|||
if(principaltype.lower()=='user'): |
|||
endpoint=endpoint+'?additionalUser='+name |
|||
else: |
|||
endpoint=endpoint+'?additionalGroup='+name |
|||
method='post' |
|||
accept='application/vnd.sas.authorization.explanations+json' |
|||
content='application/vnd.sas.selection+json' |
|||
inputdata={"resources":[explainuri]} |
|||
|
|||
decisions_result_json=callrestapi(endpoint,method,accept,content,inputdata) |
|||
|
|||
#print(decisions_result_json) |
|||
#print('decisions_result_json is a '+type(decisions_result_json).__name__+' object') #decisions_result_json is a dict object |
|||
e = decisions_result_json['explanations'][explainuri] |
|||
|
|||
#print('e is a '+type(e).__name__+' object') #e is a list object |
|||
|
|||
# Print header row if header argument was specified |
|||
if header: |
|||
if printpath: |
|||
if convey: |
|||
print('path,principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
|||
else: |
|||
print('path,principal,'+','.join(map(str, permissions))) |
|||
else: |
|||
if convey: |
|||
print('principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
|||
else: |
|||
print('principal,'+','.join(map(str, permissions))) |
|||
|
|||
principal_found=False |
|||
|
|||
#For each principle's section in the explanations section of the data returned from the REST API call... |
|||
for pi in e: |
|||
#print pi['principal'] |
|||
#We are starting a new principal, so initialise some variables for this principal |
|||
outstr='' |
|||
has_a_direct_grant_or_deny=False |
|||
if printpath: |
|||
outstr=outstr+resultpath+',' |
|||
# If a name and principaltype are provided as arguments, we will only output a row for that principal |
|||
if name and principaltype: |
|||
if 'name' in pi['principal']: |
|||
if (pi['principal']['name'].lower() == name.lower()): |
|||
principal_found=True |
|||
outstr=outstr+pi['principal']['name'] |
|||
# Permissions on object |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
# Note that some objects do have permissions which are not meaningful for that object. |
|||
# E.g. SASAdministrators are granted Add and Remove on reports, by an OOTB rule which grants SASAdministrators all permissions (including Add and Remove) on /**. |
|||
# Meanwhile, Add and Remove are not shown in the View or Edit Authotizations dialogs for reports in EV etc. |
|||
# So, while it may be correct for the /authorization/decisions endpoint to explain that SASAdministrators are granted Add and Remove on a report, |
|||
# that does not alter the fact that in the context of a report, Add and Remove permissions are not meaningful. |
|||
if pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['result'] |
|||
if 'grantFactor' in pi[permission.lower()]: |
|||
if 'direct' in pi[permission.lower()]['grantFactor']: |
|||
if pi[permission.lower()]['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
# Conveyed permissions |
|||
if convey: |
|||
for permission in permissions: |
|||
# Only a few objects have conveyed permissions at all |
|||
if 'conveyedExplanation' in pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
|||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
|||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
|||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
if direct_only: |
|||
if has_a_direct_grant_or_deny: |
|||
print(outstr) |
|||
else: |
|||
print(outstr) |
|||
# But if no name or principaltype are provided, we output all rows |
|||
else: |
|||
if 'name' in pi['principal']: |
|||
outstr=outstr+pi['principal']['name'] |
|||
else: |
|||
outstr=outstr+pi['principal']['type'] |
|||
# Permissions on object |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
if pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['result'] |
|||
if 'grantFactor' in pi[permission.lower()]: |
|||
if 'direct' in pi[permission.lower()]['grantFactor']: |
|||
if pi[permission.lower()]['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
# Conveyed permissions |
|||
if convey: |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
if 'conveyedExplanation' in pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
|||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
|||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
|||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
if direct_only: |
|||
if has_a_direct_grant_or_deny: |
|||
print(outstr) |
|||
else: |
|||
print(outstr) |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# explainaccess.py |
|||
# November 2018 |
|||
# |
|||
# Usage: |
|||
# explainaccess.py [-f folderpath | -u objectURI] [-n name_of_user_or_group -t user|group] [-p] [--header] [--direct_only] [-l permissions_list] [-c true|false] [-d] |
|||
# |
|||
# Examples: |
|||
# |
|||
# 1. Explain direct and indirect permissions on the folder /folderA/folderB, no header row. For folders, conveyed permissions are shown by default. |
|||
# ./explainaccess.py -f /folderA/folderB |
|||
# |
|||
# 2. As 1. but for a specific user named Heather |
|||
# ./explainaccess.py -f /folderA/folderB -n Heather -t user |
|||
# |
|||
# 3. As 1. with a header row |
|||
# ./explainaccess.py -f /folderA/folderB --header |
|||
# |
|||
# 4. As 1. with a header row and the folder path, which is useful if you concatenate sets of results in one file |
|||
# ./explainaccess.py -f /folderA/folderB -p --header |
|||
# |
|||
# 5. As 1. showing only rows which include a direct grant or prohibit |
|||
# ./explainaccess.py -f /folderA/folderB --direct_only |
|||
# |
|||
# 6. Explain direct and indirect permissions on a service endpoint. Note in the results that there are no conveyed permissions. |
|||
# By default they are not shown for URIs. |
|||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard |
|||
# |
|||
# 7. As 6. but including a header row and the create permission, which is relevant for services but not for folders and other objects |
|||
# ./explainaccess.py -u /SASEnvironmentManager/dashboard --header -l read update delete secure add remove create |
|||
# |
|||
# 8. Explain direct and indirect permissions on a report, reducing the permissions reported to just read, update, delete and secure, |
|||
# since none of add, remove or create are applicable to a report. |
|||
# ./explainaccess.py -u /reports/reports/e2e0e601-b5a9-4601-829a-c5137f7441c6 --header -l read update delete secure |
|||
# |
|||
# 9. Explain direct and indirect permissions on a folder expressed as a URI. Keep the default permissions list, but for completeness |
|||
# we must also specify -c true to request conveyed permissions be displayed, as they are not displayed by default for URIs. |
|||
# ./explainaccess.py -u /folders/folders/9145d26a-2c0d-4523-8835-ad186bb57fa6 --header -p -c true |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
|
|||
clidir='/opt/sas/viya/home/bin/' |
|||
debug=False |
|||
direct_only=False |
|||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
|||
default_permissions=['read','update','delete','secure','add','remove'] |
|||
#direct_permission_suffix=u"\u2666" #Black diamond suit symbol - ok in stdout, seems to cause problems with other tools |
|||
direct_permission_suffix='*' |
|||
|
|||
|
|||
# Import Python modules |
|||
|
|||
import argparse |
|||
import subprocess |
|||
import json |
|||
import sys |
|||
|
|||
from sharedfunctions import getfolderid,callrestapi |
|||
|
|||
# Define exception handler so that we only output trace info from errors when in debug mode |
|||
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook): |
|||
if debug: |
|||
debug_hook(exception_type, exception, traceback) |
|||
else: |
|||
print "%s: %s" % (exception_type.__name__, exception) |
|||
|
|||
sys.excepthook = exception_handler |
|||
|
|||
parser = argparse.ArgumentParser() |
|||
parser.add_argument("-f","--folderpath", help="Path to a Viya folder. You must specify either -f folderpath or -u objectURI.") |
|||
parser.add_argument("-u","--objecturi", help="Object URI. You must specify either -f folderpath or -u objectURI.") |
|||
parser.add_argument("-n","--name", help="Enter the name of the user or group to test.") |
|||
parser.add_argument("-t","--principaltype", help="Enter the type of principal to test: user or group.",choices=['user','group']) |
|||
parser.add_argument("-p","--printpath", action='store_true', help="Print the folder path in each row") |
|||
parser.add_argument("--header", action='store_true', help="Print a header row") |
|||
parser.add_argument("--direct_only", action='store_true', help="Show only explanations which include a direct grant or prohibit") |
|||
parser.add_argument("-l","--permissions_list", nargs="+", help="List of permissions, to include instead of all seven by default", default=default_permissions) |
|||
parser.add_argument("-c","--convey", help="Show conveyed permissions in results. True by default when folder path is specified. False by dfefault if Object URI is specified.",choices=['true','false']) |
|||
parser.add_argument("-d","--debug", action='store_true', help="Debug") |
|||
args = parser.parse_args() |
|||
path_to_folder=args.folderpath |
|||
objecturi=args.objecturi |
|||
name=args.name |
|||
principaltype=args.principaltype |
|||
printpath=args.printpath |
|||
header=args.header |
|||
direct_only=args.direct_only |
|||
permissions=args.permissions_list |
|||
conveyparam=args.convey |
|||
debug=args.debug |
|||
|
|||
if path_to_folder and objecturi: |
|||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI, but not both.') |
|||
if path_to_folder is None and objecturi is None: |
|||
raise Exception('You must specify either -f and a Viya folder path, or -u and an object URI. You may not specify both.') |
|||
|
|||
if name and principaltype is None: |
|||
raise Exception('If you specify a principal name, you must also specify a principal type which can be user or group.') |
|||
if principaltype and name is None: |
|||
raise Exception('If you specify a principal type, you must also specify a principal name.') |
|||
|
|||
for permission in permissions: |
|||
if permission not in valid_permissions: |
|||
raise Exception(permission+' is not the name of a permission. Valid permissions are: '+' '.join(map(str, valid_permissions))) |
|||
|
|||
# Two ways this program can be used: for a folder, or for a URI. |
|||
if path_to_folder: |
|||
getfolderid_result_json=getfolderid(path_to_folder) |
|||
|
|||
if (debug): |
|||
print(getfolderid_result_json) |
|||
|
|||
|
|||
if getfolderid_result_json[0] is not None: |
|||
folder_uri=getfolderid_result_json[1] |
|||
if (debug): |
|||
print("Id = "+getfolderid_result_json[0]) |
|||
print("URI = "+folder_uri) |
|||
print("Path = "+getfolderid_result_json[2]) |
|||
|
|||
explainuri=folder_uri |
|||
resultpath=path_to_folder |
|||
#Set convey to true, unless user overrode that setting and asked for false |
|||
if(conveyparam is not None and conveyparam.lower()=='false'): |
|||
convey=False |
|||
else: |
|||
convey=True |
|||
|
|||
else: |
|||
explainuri=objecturi |
|||
# This tool explains the permissions of any object. |
|||
# If the object is a folder, we expect the user to supply path_to_folder, and we find its ID |
|||
# If the object is something else, we don't have the path to the object. |
|||
# It might be possible to get the path to the object from it's ID, but I'm not sure if there is a universal way to do that. |
|||
# If the object is a report, you can call e.g. |
|||
# /opt/sas/viya/home/bin/sas-admin --output text reports show-info -id 43de1f98-d7ef-4490-bb46-cc177f995052 |
|||
# And the folder is one of the results passed back. But that call uses the reports plug-in to sas-admin and |
|||
# should not be expected to return the path to other objects. |
|||
# Plus, some objects do not have a path: service endpoints, for example. |
|||
# This is a possible area for future improvement. |
|||
resultpath=objecturi |
|||
#Set convey to false, unless user overrode that setting and asked for true |
|||
if(conveyparam is not None and conveyparam.lower()=='true'): |
|||
convey=True |
|||
else: |
|||
convey=False |
|||
|
|||
|
|||
#Use the /authorization/decision endpoint to ask for an explanation of the rules that are relevant to principals on this URI |
|||
#See Authorization API documentation in swagger at http://swagger.na.sas.com/apis/authorization/v4/apidoc.html#op:createExplanation |
|||
endpoint='/authorization/decision' |
|||
if name and principaltype: |
|||
if(principaltype.lower()=='user'): |
|||
endpoint=endpoint+'?additionalUser='+name |
|||
else: |
|||
endpoint=endpoint+'?additionalGroup='+name |
|||
method='post' |
|||
accept='application/vnd.sas.authorization.explanations+json' |
|||
content='application/vnd.sas.selection+json' |
|||
inputdata={"resources":[explainuri]} |
|||
|
|||
decisions_result_json=callrestapi(endpoint,method,accept,content,inputdata) |
|||
|
|||
#print(decisions_result_json) |
|||
#print('decisions_result_json is a '+type(decisions_result_json).__name__+' object') #decisions_result_json is a dict object |
|||
e = decisions_result_json['explanations'][explainuri] |
|||
|
|||
#print('e is a '+type(e).__name__+' object') #e is a list object |
|||
|
|||
# Print header row if header argument was specified |
|||
if header: |
|||
if printpath: |
|||
if convey: |
|||
print('path,principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
|||
else: |
|||
print('path,principal,'+','.join(map(str, permissions))) |
|||
else: |
|||
if convey: |
|||
print('principal,'+','.join(map(str, permissions))+','+','.join(map('{0}(convey)'.format, permissions))) |
|||
else: |
|||
print('principal,'+','.join(map(str, permissions))) |
|||
|
|||
principal_found=False |
|||
|
|||
#For each principle's section in the explanations section of the data returned from the REST API call... |
|||
for pi in e: |
|||
#print pi['principal'] |
|||
#We are starting a new principal, so initialise some variables for this principal |
|||
outstr='' |
|||
has_a_direct_grant_or_deny=False |
|||
if printpath: |
|||
outstr=outstr+resultpath+',' |
|||
# If a name and principaltype are provided as arguments, we will only output a row for that principal |
|||
if name and principaltype: |
|||
if 'name' in pi['principal']: |
|||
if (pi['principal']['name'].lower() == name.lower()): |
|||
principal_found=True |
|||
outstr=outstr+pi['principal']['name'] |
|||
# Permissions on object |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
# Note that some objects do have permissions which are not meaningful for that object. |
|||
# E.g. SASAdministrators are granted Add and Remove on reports, by an OOTB rule which grants SASAdministrators all permissions (including Add and Remove) on /**. |
|||
# Meanwhile, Add and Remove are not shown in the View or Edit Authotizations dialogs for reports in EV etc. |
|||
# So, while it may be correct for the /authorization/decisions endpoint to explain that SASAdministrators are granted Add and Remove on a report, |
|||
# that does not alter the fact that in the context of a report, Add and Remove permissions are not meaningful. |
|||
if pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['result'] |
|||
if 'grantFactor' in pi[permission.lower()]: |
|||
if 'direct' in pi[permission.lower()]['grantFactor']: |
|||
if pi[permission.lower()]['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
# Conveyed permissions |
|||
if convey: |
|||
for permission in permissions: |
|||
# Only a few objects have conveyed permissions at all |
|||
if 'conveyedExplanation' in pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
|||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
|||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
|||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
if direct_only: |
|||
if has_a_direct_grant_or_deny: |
|||
print(outstr) |
|||
else: |
|||
print(outstr) |
|||
# But if no name or principaltype are provided, we output all rows |
|||
else: |
|||
if 'name' in pi['principal']: |
|||
outstr=outstr+pi['principal']['name'] |
|||
else: |
|||
outstr=outstr+pi['principal']['type'] |
|||
# Permissions on object |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
if pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['result'] |
|||
if 'grantFactor' in pi[permission.lower()]: |
|||
if 'direct' in pi[permission.lower()]['grantFactor']: |
|||
if pi[permission.lower()]['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
# Conveyed permissions |
|||
if convey: |
|||
for permission in permissions: |
|||
# Not all objects have all the permissions |
|||
if 'conveyedExplanation' in pi[permission.lower()]: |
|||
# This permission was in the expanation for this principal |
|||
outstr=outstr+','+pi[permission.lower()]['conveyedExplanation']['result'] |
|||
if 'grantFactor' in pi[permission.lower()]['conveyedExplanation']: |
|||
if 'direct' in pi[permission.lower()]['conveyedExplanation']['grantFactor']: |
|||
if pi[permission.lower()]['conveyedExplanation']['grantFactor']['direct']: |
|||
has_a_direct_grant_or_deny=True |
|||
outstr=outstr+direct_permission_suffix |
|||
else: |
|||
# This permission was absent from the expanation for this principal |
|||
outstr=outstr+',' |
|||
if direct_only: |
|||
if has_a_direct_grant_or_deny: |
|||
print(outstr) |
|||
else: |
|||
print(outstr) |
|||
|
|||
@ -1,124 +1,124 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# listrules.py |
|||
# August 2018 |
|||
# |
|||
# listrulesforidentity |
|||
# |
|||
# Change History |
|||
# December 2018 - Added custom CSV output code, which writes out consistent columns in a specific order for the result rules JSON |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
import argparse |
|||
|
|||
from sharedfunctions import callrestapi, printresult |
|||
|
|||
# setup command-line arguements |
|||
parser = argparse.ArgumentParser(description="List rules for a principal and/or an endpoint") |
|||
|
|||
parser.add_argument("-u","--uri", help="Enter a string that the objecturi contains.",default="none") |
|||
parser.add_argument("-p","--principal", help="Enter the identity name or authenticatedUsers, everyone or guest",default='none') |
|||
parser.add_argument("-o","--output", help="Output Style", choices=['csv','json','simple'],default='json') |
|||
|
|||
args = parser.parse_args() |
|||
objuri=args.uri |
|||
ident=args.principal |
|||
output_style=args.output |
|||
|
|||
# set the limit high so that all data is returned |
|||
limitval=10000 |
|||
|
|||
# Define columns we want to output for each rule item (whether the item has a value for that column or not) |
|||
desired_output_columns=['objectUri','containerUri','principalType','principal','setting','permissions','description','reason','createdBy','createdTimestamp','modifiedBy','modifiedTimestamp','condition','matchParams','mediaType','enabled','version'] |
|||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
|||
|
|||
# build the request depending on what options were passed in |
|||
if ident.lower()=='authenticatedusers': ident='authenticatedUsers' |
|||
|
|||
if ident=='none' and objuri=='none': reqval= "/authorization/rules" |
|||
elif ident=='none' and objuri != 'none': reqval= "/authorization/rules?filter=contains(objectUri,'"+objuri+"')" |
|||
elif ident!='none' and objuri == 'none': |
|||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
|||
reqval= "/authorization/rules?filter=eq(principalType,'"+ident+"')" |
|||
else: |
|||
reqval= "/authorization/rules?filter=eq(principal,'"+ident+"')" |
|||
elif ident!='none' and objuri != 'none': |
|||
|
|||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
|||
reqval= "/authorization/rules?filter=and(eq(principalType,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
|||
else: |
|||
reqval= "/authorization/rules?filter=and(eq(principal,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
|||
|
|||
if ident=='none' and objuri=='none': reqval=reqval+'?limit='+str(limitval) |
|||
else: reqval=reqval+'&limit='+str(limitval) |
|||
|
|||
reqtype='get' |
|||
|
|||
#make the rest call |
|||
rules_result_json=callrestapi(reqval,reqtype) |
|||
|
|||
#print(rules_result_json) |
|||
#print('rules_result_json is a '+type(rules_result_json).__name__+' object') #rules_result_json is a dict object |
|||
|
|||
#print the result if output style is json or simple |
|||
if output_style in ['json','simple']: |
|||
printresult(rules_result_json,output_style) |
|||
elif output_style=='csv': |
|||
# Print a header row |
|||
print(','.join(map(str,desired_output_columns))) |
|||
if 'items' in rules_result_json: |
|||
#print "There are " + str(rules_result_json['count']) + " rules" |
|||
for item in rules_result_json['items']: |
|||
outstr='' |
|||
#print(item) |
|||
for column in desired_output_columns: |
|||
# Add a comma to the output string, even if we will not output anything else, unless this is the very first desired output column |
|||
if column is not desired_output_columns[0]: outstr=outstr+',' |
|||
if column=='setting': |
|||
# The setting value is derived from two columns: type and condition. |
|||
if 'condition' in item: |
|||
#print("Condition found") |
|||
outstr=outstr+'conditional '+item['type'] |
|||
else: |
|||
outstr=outstr+item['type'] |
|||
elif column in item: |
|||
# This column is in the results item for this rule |
|||
# Most columns are straight strings, but a few need special handling |
|||
if column in ['condition','description','reason']: |
|||
# The these strings can have values whcih contain commas, need we to quote them to avoid the commas being interpreted as column separators in the CSV |
|||
outstr=outstr+'"'+item[column]+'"' |
|||
elif column=='permissions': |
|||
# Construct a string listing each permission in the correct order, separated by spaces and surrounded by square brackets |
|||
outstr=outstr+'[' |
|||
permstr='' |
|||
# Output permissions in the order we choose, not the order they appear in the result item |
|||
for permission in valid_permissions: |
|||
for result_permission in item['permissions']: |
|||
if permission == result_permission: |
|||
# Add a space to separate permissions if this isn't the first permission |
|||
if not permstr=='': permstr=permstr+' ' |
|||
permstr=permstr+result_permission |
|||
outstr=outstr+permstr+']' |
|||
else: |
|||
# Normal column |
|||
# Some columns contain non-string values: matchParams and enabled are boolean, version is integer. Convert everything to a string. |
|||
outstr=outstr+str(item[column]) |
|||
print(outstr) |
|||
else: |
|||
print "output_style can be json, simple or csv. You specified " + output_style + " which is invalid." |
|||
|
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# listrules.py |
|||
# August 2018 |
|||
# |
|||
# listrulesforidentity |
|||
# |
|||
# Change History |
|||
# December 2018 - Added custom CSV output code, which writes out consistent columns in a specific order for the result rules JSON |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
import argparse |
|||
|
|||
from sharedfunctions import callrestapi, printresult |
|||
|
|||
# setup command-line arguements |
|||
parser = argparse.ArgumentParser(description="List rules for a principal and/or an endpoint") |
|||
|
|||
parser.add_argument("-u","--uri", help="Enter a string that the objecturi contains.",default="none") |
|||
parser.add_argument("-p","--principal", help="Enter the identity name or authenticatedUsers, everyone or guest",default='none') |
|||
parser.add_argument("-o","--output", help="Output Style", choices=['csv','json','simple'],default='json') |
|||
|
|||
args = parser.parse_args() |
|||
objuri=args.uri |
|||
ident=args.principal |
|||
output_style=args.output |
|||
|
|||
# set the limit high so that all data is returned |
|||
limitval=10000 |
|||
|
|||
# Define columns we want to output for each rule item (whether the item has a value for that column or not) |
|||
desired_output_columns=['objectUri','containerUri','principalType','principal','setting','permissions','description','reason','createdBy','createdTimestamp','modifiedBy','modifiedTimestamp','condition','matchParams','mediaType','enabled','version'] |
|||
valid_permissions=['read','update','delete','secure','add','remove','create'] |
|||
|
|||
# build the request depending on what options were passed in |
|||
if ident.lower()=='authenticatedusers': ident='authenticatedUsers' |
|||
|
|||
if ident=='none' and objuri=='none': reqval= "/authorization/rules" |
|||
elif ident=='none' and objuri != 'none': reqval= "/authorization/rules?filter=contains(objectUri,'"+objuri+"')" |
|||
elif ident!='none' and objuri == 'none': |
|||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
|||
reqval= "/authorization/rules?filter=eq(principalType,'"+ident+"')" |
|||
else: |
|||
reqval= "/authorization/rules?filter=eq(principal,'"+ident+"')" |
|||
elif ident!='none' and objuri != 'none': |
|||
|
|||
if ident=='guest' or ident=='everyone' or ident=='authenticatedUsers': |
|||
reqval= "/authorization/rules?filter=and(eq(principalType,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
|||
else: |
|||
reqval= "/authorization/rules?filter=and(eq(principal,'"+ident+"'),contains(objectUri,'"+objuri+"'))" |
|||
|
|||
if ident=='none' and objuri=='none': reqval=reqval+'?limit='+str(limitval) |
|||
else: reqval=reqval+'&limit='+str(limitval) |
|||
|
|||
reqtype='get' |
|||
|
|||
#make the rest call |
|||
rules_result_json=callrestapi(reqval,reqtype) |
|||
|
|||
#print(rules_result_json) |
|||
#print('rules_result_json is a '+type(rules_result_json).__name__+' object') #rules_result_json is a dict object |
|||
|
|||
#print the result if output style is json or simple |
|||
if output_style in ['json','simple']: |
|||
printresult(rules_result_json,output_style) |
|||
elif output_style=='csv': |
|||
# Print a header row |
|||
print(','.join(map(str,desired_output_columns))) |
|||
if 'items' in rules_result_json: |
|||
#print "There are " + str(rules_result_json['count']) + " rules" |
|||
for item in rules_result_json['items']: |
|||
outstr='' |
|||
#print(item) |
|||
for column in desired_output_columns: |
|||
# Add a comma to the output string, even if we will not output anything else, unless this is the very first desired output column |
|||
if column is not desired_output_columns[0]: outstr=outstr+',' |
|||
if column=='setting': |
|||
# The setting value is derived from two columns: type and condition. |
|||
if 'condition' in item: |
|||
#print("Condition found") |
|||
outstr=outstr+'conditional '+item['type'] |
|||
else: |
|||
outstr=outstr+item['type'] |
|||
elif column in item: |
|||
# This column is in the results item for this rule |
|||
# Most columns are straight strings, but a few need special handling |
|||
if column in ['condition','description','reason']: |
|||
# The these strings can have values whcih contain commas, need we to quote them to avoid the commas being interpreted as column separators in the CSV |
|||
outstr=outstr+'"'+item[column]+'"' |
|||
elif column=='permissions': |
|||
# Construct a string listing each permission in the correct order, separated by spaces and surrounded by square brackets |
|||
outstr=outstr+'[' |
|||
permstr='' |
|||
# Output permissions in the order we choose, not the order they appear in the result item |
|||
for permission in valid_permissions: |
|||
for result_permission in item['permissions']: |
|||
if permission == result_permission: |
|||
# Add a space to separate permissions if this isn't the first permission |
|||
if not permstr=='': permstr=permstr+' ' |
|||
permstr=permstr+result_permission |
|||
outstr=outstr+permstr+']' |
|||
else: |
|||
# Normal column |
|||
# Some columns contain non-string values: matchParams and enabled are boolean, version is integer. Convert everything to a string. |
|||
outstr=outstr+str(item[column]) |
|||
print(outstr) |
|||
else: |
|||
print "output_style can be json, simple or csv. You specified " + output_style + " which is invalid." |
|||
|
|||
|
|||
@ -1,59 +1,59 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# IMPORTANT: calls the sas-admin cli change the variable below if your CLI is not |
|||
# installed in the default location |
|||
# |
|||
# usage python loginviauthinfo.py |
|||
# |
|||
# Change History |
|||
# |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
from __future__ import print_function |
|||
import netrc |
|||
import subprocess |
|||
import platform |
|||
import os |
|||
import argparse |
|||
|
|||
# CHANGE THIS VARIABLE IF YOUR CLI IS IN A DIFFERENT LOCATION |
|||
clidir='/opt/sas/viya/home/bin/' |
|||
#clidir='c:\\admincli\\' |
|||
|
|||
# get input parameters |
|||
parser = argparse.ArgumentParser(description="Authinfo File") |
|||
parser.add_argument("-f","--file", help="Enter the path to the authinfo file.",default='.authinfo') |
|||
args = parser.parse_args() |
|||
authfile=args.file |
|||
|
|||
host=platform.node() |
|||
|
|||
# Read from the authinfo file in your home directory |
|||
fname=os.path.join(os.path.expanduser('~'),authfile) |
|||
|
|||
cur_profile=os.environ.get("SAS_CLI_PROFILE","Default") |
|||
print("Logging in with profile: ",cur_profile ) |
|||
|
|||
if os.path.isfile(fname): |
|||
|
|||
secrets = netrc.netrc(fname) |
|||
username, account, password = secrets.authenticators( host ) |
|||
command=clidir+'sas-admin --profile '+cur_profile+ ' auth login -u '+username+ ' -p '+password |
|||
subprocess.call(command, shell=True) |
|||
|
|||
else: |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# IMPORTANT: calls the sas-admin cli change the variable below if your CLI is not |
|||
# installed in the default location |
|||
# |
|||
# usage python loginviauthinfo.py |
|||
# |
|||
# Change History |
|||
# |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
from __future__ import print_function |
|||
import netrc |
|||
import subprocess |
|||
import platform |
|||
import os |
|||
import argparse |
|||
|
|||
# CHANGE THIS VARIABLE IF YOUR CLI IS IN A DIFFERENT LOCATION |
|||
clidir='/opt/sas/viya/home/bin/' |
|||
#clidir='c:\\admincli\\' |
|||
|
|||
# get input parameters |
|||
parser = argparse.ArgumentParser(description="Authinfo File") |
|||
parser.add_argument("-f","--file", help="Enter the path to the authinfo file.",default='.authinfo') |
|||
args = parser.parse_args() |
|||
authfile=args.file |
|||
|
|||
host=platform.node() |
|||
|
|||
# Read from the authinfo file in your home directory |
|||
fname=os.path.join(os.path.expanduser('~'),authfile) |
|||
|
|||
cur_profile=os.environ.get("SAS_CLI_PROFILE","Default") |
|||
print("Logging in with profile: ",cur_profile ) |
|||
|
|||
if os.path.isfile(fname): |
|||
|
|||
secrets = netrc.netrc(fname) |
|||
username, account, password = secrets.authenticators( host ) |
|||
command=clidir+'sas-admin --profile '+cur_profile+ ' auth login -u '+username+ ' -p '+password |
|||
subprocess.call(command, shell=True) |
|||
|
|||
else: |
|||
print('ERROR: '+fname+' does not exist') |
|||
@ -1,65 +1,65 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# showsetup.py |
|||
# |
|||
# output some system settings to help with debugging issues |
|||
# |
|||
# October 2018 |
|||
# |
|||
# |
|||
# Change History |
|||
# |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
import sys |
|||
import requests |
|||
import os |
|||
|
|||
from sharedfunctions import getprofileinfo |
|||
|
|||
# software versions |
|||
print("Python Version is: "+str(sys.version_info[0])+'.'+str(sys.version_info[1])) |
|||
print("Requests Version is: "+requests.__version__) |
|||
|
|||
# profile |
|||
|
|||
cur_profile=os.environ.get("SAS_CLI_PROFILE","NOTSET") |
|||
|
|||
if cur_profile=="NOTSET": |
|||
print("SAS_CLI_PROFILE environment variable not set, using Default profile") |
|||
cur_profile='Default' |
|||
else: |
|||
print("SAS_CLI_PROFILE environment variable set to profile "+ cur_profile) |
|||
|
|||
|
|||
ssl_file=os.environ.get("SSL_CERT_FILE","NOTSET") |
|||
|
|||
if ssl_file=="NOTSET": |
|||
print("SSL_CERT_FILE environment variable not set.") |
|||
else: |
|||
print("SSL_CERT_FILE environment variable set to profile "+ ssl_file) |
|||
|
|||
|
|||
r_ssl_file=os.environ.get("REQUESTS_CA_BUNDLE","NOTSET") |
|||
|
|||
if r_ssl_file=="NOTSET": |
|||
print("REQUESTS_CA_BUNDLE environment variable not set.") |
|||
else: |
|||
print("REQUESTS_CA_BUNDLE environment variable set to profile "+ r_ssl_file) |
|||
|
|||
getprofileinfo(cur_profile) |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# showsetup.py |
|||
# |
|||
# output some system settings to help with debugging issues |
|||
# |
|||
# October 2018 |
|||
# |
|||
# |
|||
# Change History |
|||
# |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the License); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# http://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
# |
|||
|
|||
import sys |
|||
import requests |
|||
import os |
|||
|
|||
from sharedfunctions import getprofileinfo |
|||
|
|||
# software versions |
|||
print("Python Version is: "+str(sys.version_info[0])+'.'+str(sys.version_info[1])) |
|||
print("Requests Version is: "+requests.__version__) |
|||
|
|||
# profile |
|||
|
|||
cur_profile=os.environ.get("SAS_CLI_PROFILE","NOTSET") |
|||
|
|||
if cur_profile=="NOTSET": |
|||
print("SAS_CLI_PROFILE environment variable not set, using Default profile") |
|||
cur_profile='Default' |
|||
else: |
|||
print("SAS_CLI_PROFILE environment variable set to profile "+ cur_profile) |
|||
|
|||
|
|||
ssl_file=os.environ.get("SSL_CERT_FILE","NOTSET") |
|||
|
|||
if ssl_file=="NOTSET": |
|||
print("SSL_CERT_FILE environment variable not set.") |
|||
else: |
|||
print("SSL_CERT_FILE environment variable set to profile "+ ssl_file) |
|||
|
|||
|
|||
r_ssl_file=os.environ.get("REQUESTS_CA_BUNDLE","NOTSET") |
|||
|
|||
if r_ssl_file=="NOTSET": |
|||
print("REQUESTS_CA_BUNDLE environment variable not set.") |
|||
else: |
|||
print("REQUESTS_CA_BUNDLE environment variable set to profile "+ r_ssl_file) |
|||
|
|||
getprofileinfo(cur_profile) |
|||
|
|||
@ -1,139 +1,139 @@ |
|||
#!/usr/bin/sh |
|||
# |
|||
# unittestsadm33.sh |
|||
# June 2018 |
|||
# |
|||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
|||
# |
|||
# Some tests are provided with example folder paths which are not likely to |
|||
# exist in your deployment. However, most tests are not dependent on any |
|||
# custom content in the deployment, and will run well on any deployment. |
|||
# |
|||
# Some tests intentionally do things which do not work, e.g. delete a folder |
|||
# which does not exist. The error message returned by the tool called is |
|||
# considered sufficient to demonstrate that it has in fact been called, and is |
|||
# working as intended. If you like, you could create content for these tests |
|||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
|||
# allow one of the tests below delete it. |
|||
# |
|||
# The following tests create new content, and do not clean up after themselves: |
|||
# 1. "Create a domain using createdomain" |
|||
# - creates or replaces domain named 'test', does not create multiple |
|||
# copies |
|||
# 2. "Create a binary backup job" |
|||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
|||
# runs, will create multiple copies |
|||
# You may wish to clean up after them manually, especially in a |
|||
# real customer environment. Study the tests and/or run them individually |
|||
# to learn more about what they create, so that you can find and delete it |
|||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
|||
# might be optional, as the created objects will not interfere with other |
|||
# content or work. |
|||
# |
|||
# Change History |
|||
# |
|||
# 01Jun2018 Initial version after refactoring tools |
|||
# 18oct2018 updated gerrulid test because -o changed to -u |
|||
# |
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
|
|||
echo "Return all the rest calls that can be made to the folders endpoint" |
|||
./callrestapi.py -e /folders -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get |
|||
echo |
|||
|
|||
echo "Return simple text for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get -o simple |
|||
echo |
|||
|
|||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
|||
echo "in this call set a limit above the total items to see everything" |
|||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
|||
echo |
|||
|
|||
echo "Return the json for all the identities" |
|||
./callrestapi.py -e /identities/identities -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the identities output to a file" |
|||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
|||
echo |
|||
echo "Contents of /tmp/identities.json:" |
|||
cat /tmp/identities.json |
|||
echo "End of contents of /tmp/identities.json" |
|||
echo |
|||
echo "Deleting /tmp/identities.json" |
|||
rm /tmp/identities.json |
|||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
|||
ls -al /tmp/identities.json |
|||
echo |
|||
|
|||
echo "Refresh the identities cache" |
|||
./callrestapi.py -e /identities/userCount -m get |
|||
./callrestapi.py -e /identities/cache/refreshes -m post |
|||
echo |
|||
|
|||
echo "Pass the folder path and return the folder id and uri" |
|||
./getfolderid.py -f /gelcontent |
|||
echo |
|||
|
|||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolder.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Return a set of configuration properties" |
|||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
|||
echo |
|||
|
|||
echo "Create a domain using createdomain" |
|||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HRs,Sales" |
|||
echo |
|||
|
|||
echo "Create a binary backup job" |
|||
./createbinarybackup.py |
|||
echo |
|||
|
|||
echo "Get a rule ID" |
|||
#Get /Public folder ID |
|||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
echo "The Public folder ID is" $id |
|||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
|||
echo |
|||
|
|||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
|||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
|||
echo |
|||
|
|||
echo "Test folder access" |
|||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
|||
echo |
|||
|
|||
echo "Display all sasadministrator rules" |
|||
./listrules.py --p SASadministrators -o simple |
|||
echo |
|||
|
|||
echo "Display all rules that contain SASVisual in the URI" |
|||
./listrules.py -u SASVisual -o simple |
|||
echo |
|||
#!/usr/bin/sh |
|||
# |
|||
# unittestsadm33.sh |
|||
# June 2018 |
|||
# |
|||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
|||
# |
|||
# Some tests are provided with example folder paths which are not likely to |
|||
# exist in your deployment. However, most tests are not dependent on any |
|||
# custom content in the deployment, and will run well on any deployment. |
|||
# |
|||
# Some tests intentionally do things which do not work, e.g. delete a folder |
|||
# which does not exist. The error message returned by the tool called is |
|||
# considered sufficient to demonstrate that it has in fact been called, and is |
|||
# working as intended. If you like, you could create content for these tests |
|||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
|||
# allow one of the tests below delete it. |
|||
# |
|||
# The following tests create new content, and do not clean up after themselves: |
|||
# 1. "Create a domain using createdomain" |
|||
# - creates or replaces domain named 'test', does not create multiple |
|||
# copies |
|||
# 2. "Create a binary backup job" |
|||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
|||
# runs, will create multiple copies |
|||
# You may wish to clean up after them manually, especially in a |
|||
# real customer environment. Study the tests and/or run them individually |
|||
# to learn more about what they create, so that you can find and delete it |
|||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
|||
# might be optional, as the created objects will not interfere with other |
|||
# content or work. |
|||
# |
|||
# Change History |
|||
# |
|||
# 01Jun2018 Initial version after refactoring tools |
|||
# 18oct2018 updated gerrulid test because -o changed to -u |
|||
# |
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
|
|||
echo "Return all the rest calls that can be made to the folders endpoint" |
|||
./callrestapi.py -e /folders -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get |
|||
echo |
|||
|
|||
echo "Return simple text for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get -o simple |
|||
echo |
|||
|
|||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
|||
echo "in this call set a limit above the total items to see everything" |
|||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
|||
echo |
|||
|
|||
echo "Return the json for all the identities" |
|||
./callrestapi.py -e /identities/identities -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the identities output to a file" |
|||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
|||
echo |
|||
echo "Contents of /tmp/identities.json:" |
|||
cat /tmp/identities.json |
|||
echo "End of contents of /tmp/identities.json" |
|||
echo |
|||
echo "Deleting /tmp/identities.json" |
|||
rm /tmp/identities.json |
|||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
|||
ls -al /tmp/identities.json |
|||
echo |
|||
|
|||
echo "Refresh the identities cache" |
|||
./callrestapi.py -e /identities/userCount -m get |
|||
./callrestapi.py -e /identities/cache/refreshes -m post |
|||
echo |
|||
|
|||
echo "Pass the folder path and return the folder id and uri" |
|||
./getfolderid.py -f /gelcontent |
|||
echo |
|||
|
|||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolder.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Return a set of configuration properties" |
|||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
|||
echo |
|||
|
|||
echo "Create a domain using createdomain" |
|||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HRs,Sales" |
|||
echo |
|||
|
|||
echo "Create a binary backup job" |
|||
./createbinarybackup.py |
|||
echo |
|||
|
|||
echo "Get a rule ID" |
|||
#Get /Public folder ID |
|||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
echo "The Public folder ID is" $id |
|||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
|||
echo |
|||
|
|||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
|||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
|||
echo |
|||
|
|||
echo "Test folder access" |
|||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
|||
echo |
|||
|
|||
echo "Display all sasadministrator rules" |
|||
./listrules.py --p SASadministrators -o simple |
|||
echo |
|||
|
|||
echo "Display all rules that contain SASVisual in the URI" |
|||
./listrules.py -u SASVisual -o simple |
|||
echo |
|||
|
|||
@ -1,181 +1,181 @@ |
|||
#!/usr/bin/sh |
|||
# |
|||
# unittestsadm33.sh |
|||
# December 2018 |
|||
# |
|||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
|||
# |
|||
# Some tests are provided with example folder paths which are not likely to |
|||
# exist in your deployment. However, most tests are not dependent on any |
|||
# custom content in the deployment, and will run well on any deployment. |
|||
# |
|||
# Some tests intentionally do things which do not work, e.g. delete a folder |
|||
# which does not exist. The error message returned by the tool called is |
|||
# considered sufficient to demonstrate that it has in fact been called, and is |
|||
# working as intended. If you like, you could create content for these tests |
|||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
|||
# allow one of the tests below delete it. |
|||
# |
|||
# The following tests create new content, and do not clean up after themselves: |
|||
# 1. "Create a domain using createdomain" |
|||
# - creates or replaces domain named 'test', does not create multiple |
|||
# copies |
|||
# 2. "Create a binary backup job" |
|||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
|||
# runs, will create multiple copies |
|||
# You may wish to clean up after them manually, especially in a |
|||
# real customer environment. Study the tests and/or run them individually |
|||
# to learn more about what they create, so that you can find and delete it |
|||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
|||
# might be optional, as the created objects will not interfere with other |
|||
# content or work. |
|||
# |
|||
# Change History |
|||
# |
|||
# 01Jun2018 Initial version after refactoring tools |
|||
# 18Oct2018 updated gerrulid test because -o changed to -u |
|||
# 03Dec2018 Added tests for explainaccess.py |
|||
# |
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
|
|||
echo "Return all the rest calls that can be made to the folders endpoint" |
|||
./callrestapi.py -e /folders -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get |
|||
echo |
|||
|
|||
echo "Return simple text for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get -o simple |
|||
echo |
|||
|
|||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
|||
echo "in this call set a limit above the total items to see everything" |
|||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
|||
echo |
|||
|
|||
echo "Return the json for all the identities" |
|||
./callrestapi.py -e /identities/identities -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the identities output to a file" |
|||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
|||
echo |
|||
echo "Contents of /tmp/identities.json:" |
|||
cat /tmp/identities.json |
|||
echo "End of contents of /tmp/identities.json" |
|||
echo |
|||
echo "Deleting /tmp/identities.json" |
|||
rm /tmp/identities.json |
|||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
|||
ls -al /tmp/identities.json |
|||
echo |
|||
|
|||
echo "Refresh the identities cache" |
|||
./callrestapi.py -e /identities/userCount -m get |
|||
./callrestapi.py -e /identities/cache/refreshes -m post |
|||
echo |
|||
|
|||
echo "Pass the folder path and return the folder id and uri" |
|||
./getfolderid.py -f /gelcontent |
|||
echo |
|||
|
|||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolder.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Return a set of configuration properties" |
|||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
|||
echo |
|||
|
|||
echo "Create a domain using createdomain" |
|||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR,Sales" |
|||
echo |
|||
|
|||
# Commented out for Viya 3.4 version: this tool is only intended for use with Viya 3.3 |
|||
#echo "Create a binary backup job" |
|||
#./createbinarybackup.py |
|||
#echo |
|||
|
|||
echo "Get a rule ID" |
|||
#Get /Public folder ID |
|||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
echo "The Public folder ID is" $id |
|||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
|||
echo |
|||
|
|||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
|||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
|||
echo |
|||
|
|||
echo "Test folder access" |
|||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
|||
echo |
|||
|
|||
echo "Display all sasadministrator rules" |
|||
./listrules.py --p SASadministrators -o simple |
|||
echo |
|||
|
|||
echo "Display all rules that contain SASVisual in the URI" |
|||
./listrules.py -u SASVisual -o simple |
|||
echo |
|||
|
|||
echo "Create folders from a CSV file" |
|||
./createfolders.py -h |
|||
echo |
|||
|
|||
echo Update the theme for the user sasadm |
|||
./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row." |
|||
./explainaccess.py -f /gelcontent/GELCorp |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row, for Heather." |
|||
./explainaccess.py -f /gelcontent/GELCorp -n Heather -t user |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with a header row, and include the folder path." |
|||
./explainaccess.py -f /gelcontent/GELCorp --header -p |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, showing only rows with at least one direct permission." |
|||
./explainaccess.py -f /gelcontent/GELCorp --direct_only |
|||
echo |
|||
|
|||
echo "Explain permissions for several application capabilities. Notice that there are no conveyed permissions in the results" |
|||
./explainaccess.py -u /SASEnvironmentManager/dashboard --header -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASDataStudio/** -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASDataExplorer/** -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASVisualAnalytics_capabilities/buildAnalyticalModel -p -l read update delete secure add remove create |
|||
echo |
|||
|
|||
echo "Explain the permissions for a folder expressed as a URI. This works with any kind of object, not just folders" |
|||
echo "Uses the default permissions list. Specify -c true to include conveyed permissions, as they are not included by default when you use the -u URI parameter." |
|||
#Get /gelcontent/GELCorp folder ID |
|||
./getfolderid.py --folderpath /gelcontent/GELCorp > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
./explainaccess.py -u /folders/folders/$id --header -p -c true |
|||
echo |
|||
|
|||
#!/usr/bin/sh |
|||
# |
|||
# unittestsadm33.sh |
|||
# December 2018 |
|||
# |
|||
# Calls each of the pyviyatools at least once, as a simple unit/integration test |
|||
# |
|||
# Some tests are provided with example folder paths which are not likely to |
|||
# exist in your deployment. However, most tests are not dependent on any |
|||
# custom content in the deployment, and will run well on any deployment. |
|||
# |
|||
# Some tests intentionally do things which do not work, e.g. delete a folder |
|||
# which does not exist. The error message returned by the tool called is |
|||
# considered sufficient to demonstrate that it has in fact been called, and is |
|||
# working as intended. If you like, you could create content for these tests |
|||
# to act on, e.g. create a folder called "/this_folder_does_not_exist", and |
|||
# allow one of the tests below delete it. |
|||
# |
|||
# The following tests create new content, and do not clean up after themselves: |
|||
# 1. "Create a domain using createdomain" |
|||
# - creates or replaces domain named 'test', does not create multiple |
|||
# copies |
|||
# 2. "Create a binary backup job" |
|||
# - creates a new scheduled job named 'BINARY_BACKUP_JOB' each time it |
|||
# runs, will create multiple copies |
|||
# You may wish to clean up after them manually, especially in a |
|||
# real customer environment. Study the tests and/or run them individually |
|||
# to learn more about what they create, so that you can find and delete it |
|||
# yourself. In a dev, PoC, playpen or classroom environment, the cleanup |
|||
# might be optional, as the created objects will not interfere with other |
|||
# content or work. |
|||
# |
|||
# Change History |
|||
# |
|||
# 01Jun2018 Initial version after refactoring tools |
|||
# 18Oct2018 updated gerrulid test because -o changed to -u |
|||
# 03Dec2018 Added tests for explainaccess.py |
|||
# |
|||
# |
|||
# Copyright 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
# Licensed under the Apache License, Version 2.0 (the "License"); |
|||
# you may not use this file except in compliance with the License. |
|||
# You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
# Unless required by applicable law or agreed to in writing, software |
|||
# distributed under the License is distributed on an "AS IS" BASIS, |
|||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
# See the License for the specific language governing permissions and |
|||
# limitations under the License. |
|||
|
|||
|
|||
echo "Return all the rest calls that can be made to the folders endpoint" |
|||
./callrestapi.py -e /folders -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get |
|||
echo |
|||
|
|||
echo "Return simple text for all the folders/folders" |
|||
./callrestapi.py -e /folders/folders -m get -o simple |
|||
echo |
|||
|
|||
echo "Rest calls often limit the results returned the text output will tell you returned and total available items" |
|||
echo "in this call set a limit above the total items to see everything" |
|||
./callrestapi.py -e /folders/folders?limit=500 -m get -o simple |
|||
echo |
|||
|
|||
echo "Return the json for all the identities" |
|||
./callrestapi.py -e /identities/identities -m get |
|||
echo |
|||
|
|||
echo "Return the json for all the identities output to a file" |
|||
./callrestapi.py -e /identities/identities -m get > /tmp/identities.json |
|||
echo |
|||
echo "Contents of /tmp/identities.json:" |
|||
cat /tmp/identities.json |
|||
echo "End of contents of /tmp/identities.json" |
|||
echo |
|||
echo "Deleting /tmp/identities.json" |
|||
rm /tmp/identities.json |
|||
echo "Demonstrating that /tmp/identities.json has been deleted - list it, ls should say no such file or directory:" |
|||
ls -al /tmp/identities.json |
|||
echo |
|||
|
|||
echo "Refresh the identities cache" |
|||
./callrestapi.py -e /identities/userCount -m get |
|||
./callrestapi.py -e /identities/cache/refreshes -m post |
|||
echo |
|||
|
|||
echo "Pass the folder path and return the folder id and uri" |
|||
./getfolderid.py -f /gelcontent |
|||
echo |
|||
|
|||
echo "Delete a folder based on its path - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolder.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Delete a folder and its content - we don't want to delete a real folder, so try (and fail) to delete one which does not exist" |
|||
./deletefolderandcontent.py -f /this_folder_does_not_exist |
|||
echo |
|||
|
|||
echo "Return a set of configuration properties" |
|||
./getconfigurationproperties.py -c sas.identities.providers.ldap.user |
|||
echo |
|||
|
|||
echo "Create a domain using createdomain" |
|||
./createdomain.py -t password -d test -u sasadm -p lnxsas -g "SASAdministrators,HR,Sales" |
|||
echo |
|||
|
|||
# Commented out for Viya 3.4 version: this tool is only intended for use with Viya 3.3 |
|||
#echo "Create a binary backup job" |
|||
#./createbinarybackup.py |
|||
#echo |
|||
|
|||
echo "Get a rule ID" |
|||
#Get /Public folder ID |
|||
./getfolderid.py --folderpath /Public > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
echo "The Public folder ID is" $id |
|||
./getruleid.py -u /folders/folders/$id/** -p authenticatedUsers |
|||
echo |
|||
|
|||
echo "Move all content from one folder to another folder (or in this case, the same folder)" |
|||
./movecontent.py -s /gelcontent/GELCorp/Shared/Reports -t /gelcontent/GELCorp/Shared/Reports -q |
|||
echo |
|||
|
|||
echo "Test folder access" |
|||
./testfolderaccess.py -f '/gelcontent/GELCorp' -n gelcorp -t group -m read -s grant |
|||
echo |
|||
|
|||
echo "Display all sasadministrator rules" |
|||
./listrules.py --p SASadministrators -o simple |
|||
echo |
|||
|
|||
echo "Display all rules that contain SASVisual in the URI" |
|||
./listrules.py -u SASVisual -o simple |
|||
echo |
|||
|
|||
echo "Create folders from a CSV file" |
|||
./createfolders.py -h |
|||
echo |
|||
|
|||
echo Update the theme for the user sasadm |
|||
./updatepreferences.py -t user -tn sasadm -pi OpenUI.Theme.Default -pv sas_hcb |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row." |
|||
./explainaccess.py -f /gelcontent/GELCorp |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with no header row, for Heather." |
|||
./explainaccess.py -f /gelcontent/GELCorp -n Heather -t user |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, with a header row, and include the folder path." |
|||
./explainaccess.py -f /gelcontent/GELCorp --header -p |
|||
echo |
|||
|
|||
echo "Explain permissions for the folder /gelcontent/GELCorp, showing only rows with at least one direct permission." |
|||
./explainaccess.py -f /gelcontent/GELCorp --direct_only |
|||
echo |
|||
|
|||
echo "Explain permissions for several application capabilities. Notice that there are no conveyed permissions in the results" |
|||
./explainaccess.py -u /SASEnvironmentManager/dashboard --header -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASDataStudio/** -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASDataExplorer/** -p -l read update delete secure add remove create |
|||
./explainaccess.py -u /SASVisualAnalytics_capabilities/buildAnalyticalModel -p -l read update delete secure add remove create |
|||
echo |
|||
|
|||
echo "Explain the permissions for a folder expressed as a URI. This works with any kind of object, not just folders" |
|||
echo "Uses the default permissions list. Specify -c true to include conveyed permissions, as they are not included by default when you use the -u URI parameter." |
|||
#Get /gelcontent/GELCorp folder ID |
|||
./getfolderid.py --folderpath /gelcontent/GELCorp > /tmp/folderid.txt |
|||
id=$(grep "Id " /tmp/folderid.txt | tr -s ' ' | cut -f3 -d " ") |
|||
./explainaccess.py -u /folders/folders/$id --header -p -c true |
|||
echo |
|||
|
|||
|
|||
@ -1,108 +1,108 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# updatedomain.py |
|||
# November 2018 |
|||
# |
|||
# update a viya domain to add credentials from a csv |
|||
# the domain must exist |
|||
# |
|||
# Change History |
|||
# |
|||
# 27JAN2017 Comments added |
|||
# 03DEC2018 Strip spaces from the end of users and groups |
|||
# |
|||
# csv file format |
|||
# no header row |
|||
# column1 is userid |
|||
# column2 is password |
|||
# column3 is identity |
|||
# column4 is identity type (user or group) |
|||
# For example: |
|||
# myuserid,mypass,Sales,group |
|||
# acct1,pw1,Admin,user |
|||
# etc |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
#Licensed under the Apache License, Version 2.0 (the "License"); |
|||
#you may not use this file except in compliance with the License. |
|||
#You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
#Unless required by applicable law or agreed to in writing, software |
|||
#distributed under the License is distributed on an "AS IS" BASIS, |
|||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
#See the License for the specific language governing permissions and |
|||
#limitations under the License. |
|||
|
|||
|
|||
# Update a domain |
|||
|
|||
import csv |
|||
import base64 |
|||
import argparse |
|||
|
|||
from sharedfunctions import callrestapi, file_accessible |
|||
|
|||
parser = argparse.ArgumentParser(description="Update a Viya Domain to add credentials from a csv file.") |
|||
parser.add_argument("-d","--domain", help="Existing Domain.",required=True) |
|||
parser.add_argument("-f","--file", help="A csv file containing groups and userids.",required=True) |
|||
|
|||
args = parser.parse_args() |
|||
|
|||
domain_name=args.domain |
|||
file=args.file |
|||
|
|||
# check that domain exists |
|||
reqval="/credentials/domains/"+domain_name |
|||
reqtype="get" |
|||
|
|||
#if domain does not exist call restapi will exit and no additional code is run |
|||
domainexist=callrestapi(reqval,reqtype) |
|||
|
|||
type=domainexist['type'] |
|||
|
|||
# read the csv file to create json |
|||
check=file_accessible(file,'r') |
|||
|
|||
# file can be read |
|||
if check: |
|||
|
|||
with open(file, 'rt') as f: |
|||
filecontents = csv.reader(f) |
|||
for row in filecontents: |
|||
|
|||
#print(row) |
|||
|
|||
userid=row[0] |
|||
pwval=row[1] |
|||
ident=row[2].rstrip() |
|||
identtype=row[3].rstrip() |
|||
|
|||
|
|||
if pwval: cred=base64.b64encode(pwval.encode("utf-8")).decode("utf-8") |
|||
|
|||
if identtype=="group": end_ident="groups" |
|||
if identtype=="user": end_ident="users" |
|||
|
|||
reqval="/credentials/domains/"+domain_name+"/"+end_ident+"/"+ident |
|||
reqtype="put" |
|||
|
|||
data = {} |
|||
data['domainId'] = domain_name |
|||
data['domainType'] = type |
|||
data['identityId'] = ident |
|||
data['identityType'] = identtype |
|||
data['properties']={"userId": userid} |
|||
if pwval: |
|||
data['secrets']={"password": cred} |
|||
|
|||
#print(reqval) |
|||
#print(data) |
|||
|
|||
# make the rest call |
|||
callrestapi(reqval,reqtype,data=data) |
|||
else: |
|||
print("ERROR: cannot read "+file) |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# updatedomain.py |
|||
# November 2018 |
|||
# |
|||
# update a viya domain to add credentials from a csv |
|||
# the domain must exist |
|||
# |
|||
# Change History |
|||
# |
|||
# 27JAN2017 Comments added |
|||
# 03DEC2018 Strip spaces from the end of users and groups |
|||
# |
|||
# csv file format |
|||
# no header row |
|||
# column1 is userid |
|||
# column2 is password |
|||
# column3 is identity |
|||
# column4 is identity type (user or group) |
|||
# For example: |
|||
# myuserid,mypass,Sales,group |
|||
# acct1,pw1,Admin,user |
|||
# etc |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
#Licensed under the Apache License, Version 2.0 (the "License"); |
|||
#you may not use this file except in compliance with the License. |
|||
#You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
#Unless required by applicable law or agreed to in writing, software |
|||
#distributed under the License is distributed on an "AS IS" BASIS, |
|||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
#See the License for the specific language governing permissions and |
|||
#limitations under the License. |
|||
|
|||
|
|||
# Update a domain |
|||
|
|||
import csv |
|||
import base64 |
|||
import argparse |
|||
|
|||
from sharedfunctions import callrestapi, file_accessible |
|||
|
|||
parser = argparse.ArgumentParser(description="Update a Viya Domain to add credentials from a csv file.") |
|||
parser.add_argument("-d","--domain", help="Existing Domain.",required=True) |
|||
parser.add_argument("-f","--file", help="A csv file containing groups and userids.",required=True) |
|||
|
|||
args = parser.parse_args() |
|||
|
|||
domain_name=args.domain |
|||
file=args.file |
|||
|
|||
# check that domain exists |
|||
reqval="/credentials/domains/"+domain_name |
|||
reqtype="get" |
|||
|
|||
#if domain does not exist call restapi will exit and no additional code is run |
|||
domainexist=callrestapi(reqval,reqtype) |
|||
|
|||
type=domainexist['type'] |
|||
|
|||
# read the csv file to create json |
|||
check=file_accessible(file,'r') |
|||
|
|||
# file can be read |
|||
if check: |
|||
|
|||
with open(file, 'rt') as f: |
|||
filecontents = csv.reader(f) |
|||
for row in filecontents: |
|||
|
|||
#print(row) |
|||
|
|||
userid=row[0] |
|||
pwval=row[1] |
|||
ident=row[2].rstrip() |
|||
identtype=row[3].rstrip() |
|||
|
|||
|
|||
if pwval: cred=base64.b64encode(pwval.encode("utf-8")).decode("utf-8") |
|||
|
|||
if identtype=="group": end_ident="groups" |
|||
if identtype=="user": end_ident="users" |
|||
|
|||
reqval="/credentials/domains/"+domain_name+"/"+end_ident+"/"+ident |
|||
reqtype="put" |
|||
|
|||
data = {} |
|||
data['domainId'] = domain_name |
|||
data['domainType'] = type |
|||
data['identityId'] = ident |
|||
data['identityType'] = identtype |
|||
data['properties']={"userId": userid} |
|||
if pwval: |
|||
data['secrets']={"password": cred} |
|||
|
|||
#print(reqval) |
|||
#print(data) |
|||
|
|||
# make the rest call |
|||
callrestapi(reqval,reqtype,data=data) |
|||
else: |
|||
print("ERROR: cannot read "+file) |
|||
|
|||
@ -1,99 +1,99 @@ |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# updatepreferences.py |
|||
# October 2018 |
|||
# |
|||
# Update user preferences for a single user of a group of users |
|||
# |
|||
# Change History |
|||
# |
|||
# 30OCT2018 first version |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
#Licensed under the Apache License, Version 2.0 (the "License"); |
|||
#you may not use this file except in compliance with the License. |
|||
#You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
#Unless required by applicable law or agreed to in writing, software |
|||
#distributed under the License is distributed on an "AS IS" BASIS, |
|||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
#See the License for the specific language governing permissions and |
|||
#limitations under the License. |
|||
|
|||
|
|||
#################################################################### |
|||
#### COMMAND LINE EXAMPLE #### |
|||
#################################################################### |
|||
#### ./updatepreferences.py - #### |
|||
#### -t user #### |
|||
#### -tn myUser #### |
|||
#### -pi VA.geo.drivedistance.unit #### |
|||
#### -pv kilometers #### |
|||
#################################################################### |
|||
#### POSSIBLE VALUES #### |
|||
#################################################################### |
|||
#### sas.welcome.suppress = true/false #### |
|||
#### sas.drive.show.pinned = true/false #### |
|||
#### VA.geo.drivedistance.unit = kilometers/miles #### |
|||
#### OpenUI.Theme.Default = sas_corporate/sas_inspire/sas_hcb #### |
|||
#################################################################### |
|||
|
|||
import argparse |
|||
from sharedfunctions import callrestapi |
|||
|
|||
parser = argparse.ArgumentParser(description="Update user preferences for a user or a group of users") |
|||
parser.add_argument("-t", "--target", help="Type the target of the update: user or group", required=True, choices=['user', 'group']) |
|||
parser.add_argument("-tn", "--targetname", help="ID of the user or group to which the update applies.", required=True) |
|||
parser.add_argument("-pi", "--preferenceid", help="ID of the preference to be updated", required=True) |
|||
parser.add_argument("-pv", "--preferencevalue", help="Value to be set for the preference", required=True) |
|||
|
|||
args = parser.parse_args() |
|||
target = args.target |
|||
targetName = args.targetname |
|||
preferenceID = args.preferenceid |
|||
preferenceValue = args.preferencevalue |
|||
|
|||
json= {"application": "SAS Visual Analytics", "version": 1,"id": preferenceID ,"value": preferenceValue} |
|||
|
|||
# Function to update preference of a specific user |
|||
if target == 'user' : |
|||
|
|||
userID=targetName |
|||
|
|||
reqtype='get' |
|||
reqval="/identities/users/"+userID |
|||
|
|||
userexist=callrestapi(reqval,reqtype) |
|||
|
|||
reqtype="put" |
|||
reqval="/preferences/preferences/"+ userID +"/" + preferenceID |
|||
result=callrestapi(reqval,reqtype,data=json) |
|||
print("Updating Preference "+reqval+" = "+preferenceValue) |
|||
|
|||
|
|||
else: # Execute actual code to update the preference for a user or a group |
|||
|
|||
reqtype='get' |
|||
reqval='/identities/groups/'+ targetName +'/members?limit=1000' |
|||
resultdata=callrestapi(reqval,reqtype) |
|||
|
|||
reqtype="put" |
|||
|
|||
if 'items' in resultdata: |
|||
|
|||
returned_items=len(resultdata['items']) |
|||
for i in range(0,returned_items): |
|||
|
|||
id=resultdata['items'][i]['id'] |
|||
type=resultdata['items'][i]['type'] |
|||
|
|||
if type=="user": |
|||
reqval="/preferences/preferences/"+ id +"/" + preferenceID |
|||
result=callrestapi(reqval, reqtype,data=json,stoponerror=0) |
|||
print(result) |
|||
print("Updating Preference "+reqval+" = "+preferenceValue) |
|||
#!/usr/bin/python |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# updatepreferences.py |
|||
# October 2018 |
|||
# |
|||
# Update user preferences for a single user of a group of users |
|||
# |
|||
# Change History |
|||
# |
|||
# 30OCT2018 first version |
|||
# |
|||
# Copyright © 2018, SAS Institute Inc., Cary, NC, USA. All Rights Reserved. |
|||
# |
|||
#Licensed under the Apache License, Version 2.0 (the "License"); |
|||
#you may not use this file except in compliance with the License. |
|||
#You may obtain a copy of the License at |
|||
# |
|||
# https://www.apache.org/licenses/LICENSE-2.0 |
|||
# |
|||
#Unless required by applicable law or agreed to in writing, software |
|||
#distributed under the License is distributed on an "AS IS" BASIS, |
|||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
#See the License for the specific language governing permissions and |
|||
#limitations under the License. |
|||
|
|||
|
|||
#################################################################### |
|||
#### COMMAND LINE EXAMPLE #### |
|||
#################################################################### |
|||
#### ./updatepreferences.py - #### |
|||
#### -t user #### |
|||
#### -tn myUser #### |
|||
#### -pi VA.geo.drivedistance.unit #### |
|||
#### -pv kilometers #### |
|||
#################################################################### |
|||
#### POSSIBLE VALUES #### |
|||
#################################################################### |
|||
#### sas.welcome.suppress = true/false #### |
|||
#### sas.drive.show.pinned = true/false #### |
|||
#### VA.geo.drivedistance.unit = kilometers/miles #### |
|||
#### OpenUI.Theme.Default = sas_corporate/sas_inspire/sas_hcb #### |
|||
#################################################################### |
|||
|
|||
import argparse |
|||
from sharedfunctions import callrestapi |
|||
|
|||
parser = argparse.ArgumentParser(description="Update user preferences for a user or a group of users") |
|||
parser.add_argument("-t", "--target", help="Type the target of the update: user or group", required=True, choices=['user', 'group']) |
|||
parser.add_argument("-tn", "--targetname", help="ID of the user or group to which the update applies.", required=True) |
|||
parser.add_argument("-pi", "--preferenceid", help="ID of the preference to be updated", required=True) |
|||
parser.add_argument("-pv", "--preferencevalue", help="Value to be set for the preference", required=True) |
|||
|
|||
args = parser.parse_args() |
|||
target = args.target |
|||
targetName = args.targetname |
|||
preferenceID = args.preferenceid |
|||
preferenceValue = args.preferencevalue |
|||
|
|||
json= {"application": "SAS Visual Analytics", "version": 1,"id": preferenceID ,"value": preferenceValue} |
|||
|
|||
# Function to update preference of a specific user |
|||
if target == 'user' : |
|||
|
|||
userID=targetName |
|||
|
|||
reqtype='get' |
|||
reqval="/identities/users/"+userID |
|||
|
|||
userexist=callrestapi(reqval,reqtype) |
|||
|
|||
reqtype="put" |
|||
reqval="/preferences/preferences/"+ userID +"/" + preferenceID |
|||
result=callrestapi(reqval,reqtype,data=json) |
|||
print("Updating Preference "+reqval+" = "+preferenceValue) |
|||
|
|||
|
|||
else: # Execute actual code to update the preference for a user or a group |
|||
|
|||
reqtype='get' |
|||
reqval='/identities/groups/'+ targetName +'/members?limit=1000' |
|||
resultdata=callrestapi(reqval,reqtype) |
|||
|
|||
reqtype="put" |
|||
|
|||
if 'items' in resultdata: |
|||
|
|||
returned_items=len(resultdata['items']) |
|||
for i in range(0,returned_items): |
|||
|
|||
id=resultdata['items'][i]['id'] |
|||
type=resultdata['items'][i]['type'] |
|||
|
|||
if type=="user": |
|||
reqval="/preferences/preferences/"+ id +"/" + preferenceID |
|||
result=callrestapi(reqval, reqtype,data=json,stoponerror=0) |
|||
print(result) |
|||
print("Updating Preference "+reqval+" = "+preferenceValue) |
|||
else: print("Cannot set preferences for a group "+id ) |
|||
Loading…
Reference in new issue