diff --git a/.github/workflows/DockerBuildPush.yml b/.github/workflows/DockerBuildPush.yml index 94286b7..8c13a50 100644 --- a/.github/workflows/DockerBuildPush.yml +++ b/.github/workflows/DockerBuildPush.yml @@ -19,7 +19,7 @@ jobs: tag_with_ref: true dockerfile: docker/Dockerfile - QA-DcokerImage: + QA-DockerImage: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/QAConfigMyApp.yml b/.github/workflows/QAConfigMyApp.yml index 4a58e5d..051840d 100644 --- a/.github/workflows/QAConfigMyApp.yml +++ b/.github/workflows/QAConfigMyApp.yml @@ -10,7 +10,7 @@ on: branches: [ master, develop ] jobs: - DcokerImage-QA: + DockerImage-QA: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -32,53 +32,53 @@ jobs: echo Running basic CMA pwd ls -ltr - ./start.sh -a Jenkins_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} - name: TestCase1- Basic ConfigMyApp with default dashboard off run: | echo Running basic CMA with default dashboard off pwd ls -ltr - ./start.sh -a Jenkins_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase2- BT_ONLY env: CMA_USE_HTTPS: false run: | echo Running BT_ONLY, - ./start.sh -a Jenkins_API --bt-only -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --bt-only -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase3- Action suppression. Default. run: | echo Running Action Suppression, - ./start.sh -a Jenkins_API --suppress-action -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --suppress-action -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase4- Action suppression. Date and duration. run: | echo Running Action Suppression #--suppress-start=$(date -d " + 20 minutes" -u +%FT%T) - ./start.sh -a Jenkins_API --suppress-action --suppress-duration=120 -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --suppress-action --suppress-duration=120 -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase5- Upload custom dashboard - runtime run: | echo Running Dash upload curl https://gist.githubusercontent.com/iogbole/48e7568454b066132700c4fe039c2cff/raw/4aa417193e7ce9f3cce2410e67d525761cb6d678/gistfile1.txt -o ./custom_dashboards/CustomDashboard_vanilla.json echo Running SIM and DB, - ./start.sh -a IoT_API --upload-custom-dashboard -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --upload-custom-dashboard -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase6- Upload custom dashboard - env variables run: | echo Running Dash upload curl https://gist.githubusercontent.com/iogbole/48e7568454b066132700c4fe039c2cff/raw/4aa417193e7ce9f3cce2410e67d525761cb6d678/gistfile1.txt -o ./custom_dashboards/CustomDashboard_vanilla.json export CMA_UPLOAD_CUSTOM_DASHBOARD=true - ./start.sh -a IoT_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase7- Health rules only - no overwrite - parameters env: CMA_USE_HTTPS: false run: | echo Running health rules only, get values from runtime parameters, - ./start.sh -a Jenkins_API --health-rules-only --no-health-rules-overwrite -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --health-rules-only --no-health-rules-overwrite -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase8- Health rules only - overwrite - env variables env: @@ -87,7 +87,7 @@ jobs: CMA_HEALTH_RULES_ONLY: true run: | echo Running health rules only, get values from environment variables, - ./start.sh -a Jenkins_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase9- Health rules only - overwrite default - config env: @@ -96,7 +96,7 @@ jobs: cp config.json config.json.bkp curl https://gist.githubusercontent.com/AlexJov/63ccb17421208679ef63b55afafea712/raw/b8e5ebc5399a8d7df5422ff07c49c892f0c3bd63/config.json -o ./config.json echo Running health rules only, get values from config, - ./start.sh -a Jenkins_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard cp config.json.bkp config.json - name: TestCase10- Delete health rules, existing @@ -107,29 +107,29 @@ jobs: curl https://gist.githubusercontent.com/AlexJov/03317fd4271325fbd6678dded2df6e91/raw/bb33a4b3abcaed762f1a5b262586183c6efd4402/CpuUtilisationTooHighToDelete.json -o ./health_rules/ServerVisibility/CpuUtilisationTooHighToDelete.json echo Running health rules only, import additional health rules, - ./start.sh -a Jenkins_API -u appd --include-sim --health-rules-only -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo -u appd --include-sim --health-rules-only -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard echo Delete health rules: - ./start.sh -a Jenkins_API --health-rules-delete "Agent Availability to Delete, Server Health: CPU Utilisation is too high to Delete" -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --health-rules-delete "Agent Availability to Delete, Server Health: CPU Utilisation is too high to Delete" -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase11- Delete health rules, non existing env: CMA_USE_HTTPS: false run: | echo Delete health rules, delete health rules from TestCase10 - ./start.sh -a Jenkins_API --health-rules-delete "There is no this rule name" -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --health-rules-delete "There is no this rule name" -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase12- Overwrite Health rules - runtime run: | echo Running basic CMA pwd ls -ltr - ./start.sh -a Jenkins_API --health-rules-only --overwrite-health-rules -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard + ./start.sh -a Jenkins_API_Demo --health-rules-only --overwrite-health-rules -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --no-upload-default-dashboard - name: TestCase13- Upload default dashboard SIM and DB - runtime run: | echo Running SIM and DB, runtime - ./start.sh -a IoT_API --upload-default-dashboard --include-database --database-name 'ConfigMyApp' --include-sim -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + ./start.sh -a Jenkins_API_Demo --upload-default-dashboard --include-database --database-name 'ConfigMyApp' --include-sim -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} - name: TestCase14- Upload default dashboard - env variables env: @@ -140,5 +140,46 @@ jobs: CMA_INCLUDE_SIM: true run: | echo Running SIM and DB, env vars - ./start.sh -a IoT_API -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + - name: TestCase15- rbac roles and saml groups - runtime + env: + CMA_UPLOAD_DEFAULT_DASHBOARD: false + run: | + echo Running RBAC, runtime parameters + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} --rbac-only --rbac-action="role-saml" + + - name: TestCase16- rbac roles and saml groups - env variables + env: + CMA_UPLOAD_DEFAULT_DASHBOARD: false + CMA_RBAC_ONLY: true + CMA_RBAC_ACTION: "role-saml" + CMA_RBAC_ROLE_NAME: "test-role" + CMA_RBAC_ROLE_DESCRIPTION: "test-role-desc" + CMA_RBAC_SAML_GROUP_NAME: "test-saml-group" + run: | + echo Running RBAC, env vars + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + + - name: TestCase17- rbac roles and saml groups - no names provided - env variables + env: + CMA_UPLOAD_DEFAULT_DASHBOARD: false + CMA_RBAC_ONLY: true + CMA_RBAC_ACTION: "role-saml" + run: | + echo Running RBAC, env vars + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + + - name: TestCase18- sensitive data masking - env variables + env: + CMA_UPLOAD_DEFAULT_DASHBOARD: false + CMA_DATA_MASKING: true + CMA_DATA_MASKING_PATTERNS: "-.*8090" + CMA_DATA_MASKING_STRATEGY: "exact" + run: | + echo Running sensitive data masking, env vars + ./start.sh -a Jenkins_API_Demo -c ${{ secrets.CONTROLLER_HOST }} -p ${{ secrets.CONTROLLER_USERNAME }} -u ${{ secrets.CONTROLLER_PASSWORD }} + last_log_line=$(tail -n 1 error.log) + echo "Logged: ${last_log_line}" + + diff --git a/.gitignore b/.gitignore index e86176b..21d8d12 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,7 @@ api_actions/uploaded/*.json* api_actions/actions/*.json* custom_dashboards/*.json* custom_dashboards/uploaded/*.json* +cookie.appd +rbac/restui_role_files/uploaded/*.json +rbac/restui_saml_files/uploaded/*.json +rbac/restui_license_rules_files/uploaded/*.json \ No newline at end of file diff --git a/config.json b/config.json index 8c75ef3..b0032c8 100644 --- a/config.json +++ b/config.json @@ -49,5 +49,22 @@ "suppress_upload_files": false, "suppress_delete": "" } + ], + "rbac": [ + { + "rbac_only": false, + "rbac_action": "role-saml", + "rbac_role_name": "", + "rbac_role_description": "", + "rbac_saml_group_name": "", + "rbac_license_rule_name": "" + } + ], + "sensitive_data": [ + { + "data_masking": true, + "data_masking_patterns": "-.*8090", + "data_masking_strategy": "exact" + } ] } diff --git a/docker/env.list b/docker/env.list index dbec430..265ce6a 100644 --- a/docker/env.list +++ b/docker/env.list @@ -1,6 +1,6 @@ -CMA_APPLICATION_NAME=IoT_API -CMA_CONTROLLER_HOST=configmyappdemo-2044no-uzyczrm0.appd-cx.com +CMA_APPLICATION_NAME=Jenkins_API +CMA_CONTROLLER_HOST=configmyappdemo-20103n-m3lp0zmi.appd-cx.com CMA_CONTROLLER_PORT=8090 CMA_USE_HTTPS=false CMA_USERNAME=appd diff --git a/docker/run.sh b/docker/run.sh index b1c109a..54dae65 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -15,6 +15,14 @@ fi #standard run docker run --rm --env-file env.list ${image_name}:${version} +if [ $? -eq 0 ] +then + echo "Successful Docker container run. Proceeding..." +else + echo "Error occurred. Could not run the Docker container." >&2 + exit 1 +fi + docker ps # change directory to the root folder where mounted volumes are located - if you're executing the ./run.sh script diff --git a/modules/actions/application-action-suppression.sh b/modules/actions/application-action-suppression.sh index dee3b55..7bad4a6 100755 --- a/modules/actions/application-action-suppression.sh +++ b/modules/actions/application-action-suppression.sh @@ -2,6 +2,8 @@ source ./modules/common/http_check.sh # func_check_http_status, func_check_http_response source ./modules/common/application.sh # func_get_application_id +source ./modules/common/logging.sh # func_log_error_to_file +source ./modules/common/sensitive_data.sh # func_data_masking # 1. INPUT PARAMETERS _controller_url=${1} # hostname + /controller @@ -27,8 +29,9 @@ function func_check_http_response(){ # override default cp -rf "$filePath" "./api_actions/uploaded/${fileName}.${dt}" echo "Success..." else - echo "${dt} ERROR "{$http_message_body}"" >> error.log echo "ERROR $http_message_body" + http_message_body=$(func_data_masking ${http_message_body}) + logged_to_file=$(func_log_error_to_file "${http_message_body}" "ERROR") exit 1 fi } diff --git a/modules/actions/upload-files-action-suppression.sh b/modules/actions/upload-files-action-suppression.sh index e666e1b..e4fbec9 100755 --- a/modules/actions/upload-files-action-suppression.sh +++ b/modules/actions/upload-files-action-suppression.sh @@ -2,6 +2,8 @@ source ./modules/common/http_check.sh # func_check_http_status, func_check_http_response source ./modules/common/application.sh # func_get_application_id +source ./modules/common/logging.sh # func_log_error_to_file +source ./modules/common/sensitive_data.sh # func_data_masking # 1. INPUT PARAMETERS _controller_url=${1} # hostname + /controller @@ -31,8 +33,9 @@ function func_check_http_response(){ # function override cp -rf "$filePath" "./api_actions/uploaded/${fileName}.${dt}" echo "Success..." else - echo "${dt} ERROR "{$http_message_body}"" >> error.log echo "ERROR $http_message_body" + http_message_body=$(func_data_masking ${http_message_body}) + logged_to_file=$(func_log_error_to_file "${http_message_body}" "ERROR") # do not break on failure fi } diff --git a/modules/business_transactions/configBT.sh b/modules/business_transactions/configBT.sh index 26c9c04..7c2fb42 100755 --- a/modules/business_transactions/configBT.sh +++ b/modules/business_transactions/configBT.sh @@ -2,6 +2,8 @@ # Match types: MATCHES_REGEX, CONTAINS, EQUALS, STARTS_WITH, ENDS_WITH, IS_IN_LIST, IS_NOT_EMPTY # The format of the JSON must be maintained at all times.. all four sections must be available even if you're not using them, leave them blank. +source ./modules/common/logging.sh # func_log_error_to_file + bt_folder="./bt_api_templates" bt_conf="./bt_config/configBT.json" bt_config_template="bt_config_template.xml" @@ -293,7 +295,7 @@ if [ -f "$bt_file_path" ]; then echo "The file path is $bt_file_path" sleep 1 echo "" - echo "Please wait while we configure BT detection rules in $appName" + echo "Please wait while we configure BT detection rules in $app_name" btendpoint="/transactiondetection/${app_name}/custom" @@ -303,13 +305,13 @@ if [ -f "$bt_file_path" ]; then echo "" echo "*********************************************************************" echo "ConfigMyApp created Business transaction detection rules successfully." - echo "Please check $appName detection rule configuration pages." + echo "Please check $app_name detection rule configuration pages." echo "*********************************************************************" echo "" else - msg="An Error occured whilst creating business transaction detection rules. Please refer to the error.log file for further details" - echo "${dt} An Error occured whilst creating business transaction detection rules." >> error.log - echo "${dt} ERROR $bt_response" >>error.log + msg="An Error occured whilst creating business transaction detection rules. Please refer to the error.log file for further details." + func_log_error_to_file "An Error occured whilst creating business transaction detection rules for application '$app_name'." + func_log_error_to_file "$bt_response" "ERROR" echo "$msg" echo "$bt_response" echo "" diff --git a/modules/common/http_check.sh b/modules/common/http_check.sh index c386845..02eb2a4 100644 --- a/modules/common/http_check.sh +++ b/modules/common/http_check.sh @@ -1,12 +1,18 @@ #!/bin/bash +source ./modules/common/sensitive_data.sh # func_data_masking +source ./modules/common/logging.sh # func_log_error_to_file + +# external function func_check_http_status() { local http_code=$1 local message_on_failure=$2 #echo "HTTP status code: $http_code" if [[ $http_code -lt 200 ]] || [[ $http_code -gt 299 ]]; then - echo "${dt} ERROR "{$http_code: $message_on_failure}"" >> ../../error.log - echo "$http_code: $message_on_failure" + echo "ERROR $http_code: $message_on_failure" + # mask sensitive info (if needed) + message_on_failure=$(func_data_masking "${message_on_failure}" "" "") + logged_to_file=$(func_log_error_to_file "${message_on_failure}" "ERROR" "$http_code") exit 1 fi } @@ -15,14 +21,16 @@ function func_check_http_response(){ local http_message_body="$1" local string_success_response_contains="$2" if [[ "$http_message_body" =~ "$string_success_response_contains" ]]; then # contains - echo "*********************************************************************" - echo "Success" - echo "*********************************************************************" - else - echo "${dt} ERROR "{$http_message_body}"" >> ../../error.log - echo "ERROR $http_message_body" - exit 1 - fi + echo "*********************************************************************" + echo "Success" + echo "*********************************************************************" + else + echo "ERROR HTTP response does not contain '$string_success_response_contains'. Check logs for mode detils..." + # mask sensitive info (if needed) + http_message_body=$(func_data_masking "${http_message_body}" "" "") + logged_to_file=$(func_log_error_to_file "${http_message_body}" "ERROR") + exit 1 + fi } function func_cleanup() { diff --git a/modules/common/logging.sh b/modules/common/logging.sh new file mode 100644 index 0000000..1836588 --- /dev/null +++ b/modules/common/logging.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# intent to be internal +function func_log_error_to_file(){ + local message="$1" + local severity="$2" # optional, error by default + local status_code="$3" # optional + + dt=$(date '+%Y-%m-%d_%H-%M-%S') + + if [[ -z "$severity" ]]; then + severity="ERROR" + fi + + if [[ ! -z "$status_code" ]]; then + status_code="'$status_code' " + fi + + echo "${dt} ${severity} ${status_code}"${message}"" >> error.log +} \ No newline at end of file diff --git a/modules/common/sensitive_data.sh b/modules/common/sensitive_data.sh new file mode 100755 index 0000000..4fe3005 --- /dev/null +++ b/modules/common/sensitive_data.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +#source ./modules/common/logging.sh # func_log_error_to_file + +# can be called form any part of the program => handle varaibles here +if ([ -z "${_arg_data_masking// }" ] && [ ! -z "${CMA_DATA_MASKING// }" ]); then + _arg_data_masking=${CMA_DATA_MASKING} +fi + +if ([ -z "${_arg_data_masking_patterns// }" ] && [ ! -z "${CMA_DATA_MASKING_PATTERNS// }" ]); then + _arg_data_masking_patterns=${CMA_DATA_MASKING_PATTERNS} +fi + +if ([ -z "${_arg_data_masking_strategy// }" ] && [ ! -z "${CMA_DATA_MASKING_STRATEGY// }" ]); then + _arg_data_masking_strategy=${CMA_DATA_MASKING_STRATEGY} +fi + +conf_file="config.json" + +if [[ -z "${_arg_data_masking// }" ]]; then + _arg_data_masking=$(jq -r '.sensitive_data[].data_masking' <${conf_file}) +fi +if [[ -z "${_arg_data_masking_patterns// }" ]]; then + _arg_data_masking_patterns=$(jq -r '.sensitive_data[].data_masking_patterns' <${conf_file}) +fi +if [[ -z "${_arg_data_masking_strategy// }" ]]; then + _arg_data_masking_strategy=$(jq -r '.sensitive_data[].data_masking_strategy' <${conf_file}) +fi + +## check if values are valid data type +if ([ ! $_arg_data_masking = false ] && [ ! $_arg_data_masking = true ] ); then + echo -n "Data-masking value \"${_arg_data_masking}\" not recognized. Proceeding with data not being masked..." +fi + +# source ./modules/common/sensitive_data.sh; func_data_masking "me.saas.com:443" "saas" "exact" +function func_data_masking(){ + local message="$1" + local patterns="$2" #todo no characters: comma, # or * allowed + local strategy="$3" # valid: exact, before, after + + # argumebts from configuration + if [ $_arg_data_masking = false ]; then + echo "$message" + exit 0 + fi + + if [[ -z "$patterns" ]]; then + patterns=${_arg_data_masking_patterns} + fi + + if [[ -z "$strategy" ]]; then + strategy=${_arg_data_masking_strategy} + fi + + masking_string="*********" + valid_data_masking_strategies=("exact" "before" "after") + + if [[ ! " ${valid_data_masking_strategies[@]} " =~ " ${strategy} " ]]; then + # whatever you want to do when array doesn't contain value + echo -e "[Data masking strategy \"${strategy}\" not recognized] " + fi + + for pattern in ${patterns//,/ } + do + # mask sensitive info + case $strategy in + exact) + message=$(echo $message | sed -e "s#${pattern}#${masking_string}#g") + ;; + before) + message=$(echo $message | sed -e "s#.*${pattern}#${masking_string}#g") + ;; + after) + message=$(echo $message | sed -e "s#${pattern}.*'#${masking_string}#g") + ;; + *) + # echo -n "Message not masked..." + ;; + esac + + done + + echo "$message" +} \ No newline at end of file diff --git a/modules/rbac/api_groups.sh b/modules/rbac/api_groups.sh new file mode 100755 index 0000000..40d4383 --- /dev/null +++ b/modules/rbac/api_groups.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/common/application.sh # func_get_application_id + + + +function func_get_all_groups() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${6} + + _endpoint_url="/api/rbac/v1/groups" + _method="GET" + if [[ _debug = true ]]; then _output="-v"; else _output="-s"; fi + + echo "curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}${_endpoint_url} ${_proxy_details}" + + # Get all groups + groups=$(curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}${_endpoint_url} ${_proxy_details}) + + echo "${groups}" + +} + +function func_get_group_id_by_name() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${6} + + local _group_name=${7} + + _endpoint_url="/api/rbac/v1/groups" + _method="GET" + _endpoint_url="${_endpoint_url}/name/${_group_name}" + if [ $_debug = true ]; then _output="-v"; else _output="-s"; fi + + # Get group by name + group=$(curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + + group_id=$(jq '.[] | select(.id)' <<<$group) + + if [ "$group_id" = "" ]; then + func_check_http_status 404 "Group name ${_group_name} not found." + fi + + echo "${group_id}" + +} + + +function func_create_group() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${5} + + local _group_name=${6} + local _group_description=${7} + local _group_security_provider_type="INTERNAL" + + if [ ! -z "${_group_name// }" ]; then + + _endpoint_url="/api/rbac/v1/groups" + _method="POST" + _header="Content-Type: application/vnd.appd.cntrl+json;v=1" + + _payload="{\"name\": \"${_group_name}\",\"description\": \"${_group_description}\",\"security_provider_type\": \"${_group_security_provider_type}\"}" + + if [[ $_debug = true ]]; then _output="-v"; else _output="-s"; fi + + echo "curl ${_output} -X ${_method} -H "\"${_header}\"" -d "\'${_payload}\'" --user ${_user_credentials} ${_controller_url}${_endpoint_url} ${_proxy_details}" + + httpCode=$(curl ${_output} -o /dev/null -w "%{http_code}" -X ${_method} -H "\"${_header}\"" -d "\'${_payload}\'" --user ${_user_credentials} ${_controller_url}${_endpoint_url} ${_proxy_details}) + func_check_http_status $httpCode "Error occured creating group '${_group_name}'." + else + func_check_http_status 404 "Group name must be provided." + fi + + echo "Group created: '${_group_name}'" + +} + diff --git a/modules/rbac/api_roles.sh b/modules/rbac/api_roles.sh new file mode 100755 index 0000000..ddbac44 --- /dev/null +++ b/modules/rbac/api_roles.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/common/application.sh # func_get_application_id + + + +function func_get_all_roles() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${6} + + if [[ _debug = true ]]; then echo ">> func_get_all_roles"; fi + + _endpoint_url="/api/rbac/v1/roles" + _method="GET" + if [[ _debug = true ]]; then _output="-v"; else _output="-s"; fi + + # Get all roles + allRoles=$(curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + + echo "${allRoles}" + +} + +function func_get_role_by_name() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + local _application_name=${4} + local _debug=${5} + + local _role_name=${6} + + _endpoint_url="/api/rbac/v1/roles/name/${_role_name}" + _method="GET" + if [[ _debug = true ]]; then _output="-v"; else _output="-s"; fi + + # Get all roles + response=$(curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + + echo "${response}" + +} + +function func_create_role() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${6} + + local _role_name=${7} + local _role_description=${8} + + if [[ _debug = true ]]; then echo ">> func_create_role"; fi + + if [ ! -z "${_role_name// }" ]; then + + _endpoint_url="/api/rbac/v1/roles" + _method="POST" + _header="Content-Type: application/vnd.appd.cntrl+json;v=1" + _payload="{\"name\": \"${_role_name}\",\"description\": \"${_role_description}\"}" + if [ $_debug = true ]; then _output="-v"; else _output="-s"; fi + + httpCode=$(curl ${_output} -o /dev/null -w "%{http_code}" -X ${_method} -H "${_header}" -d "${_payload}" --user ${_user_credentials} ${_controller_url}${_endpoint_url} ${_proxy_details}) + func_check_http_status $httpCode "Error occured creating a role '${_role_name}'." + else + func_check_http_status 404 "Role name must be provided." + fi + + echo "Role created '${_role_name}'" + +} + +function func_add_role_to_group() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${6} + + local _role_id=${7} + local _group_id=${8} + + if [[ _debug = true ]]; then echo ">> func_add_role_to_group"; fi + + _endpoint_url="/api/rbac/v1/roles" + _method="PUT" + _header="Content-Type: application/vnd.appd.cntrl+json;v=1" + _endpoint_url="${_endpoint_url0}/${_role_id}/groups/${_group_id}" + if [ $_debug = true ]; then _output="-v"; else _output="-s"; fi + + # Add role to a group + response=$(curl ${_output} -X ${_method} -H "${_header}" --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + #func_check_http_status $httpCode "Error occured adding role '${_role_id}' to a group '${_group_id}'." + + echo "${response}" + +} + + diff --git a/modules/rbac/api_users.sh b/modules/rbac/api_users.sh new file mode 100755 index 0000000..e0a91e0 --- /dev/null +++ b/modules/rbac/api_users.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/common/application.sh # func_get_application_id + + + +function func_get_all_users() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${5} + + _endpoint_url="/api/rbac/v1/users" + + if [[ _debug = true ]]; then _output="-v"; else _output="-s"; fi + + # Get all applications + allUsers=$(curl -s --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + + echo "${allUsers}" + +} + +function func_get_user_by_id() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _application_name=${3} + local _proxy_details=${4} + local _debug=${5} + + local _user_id=${6} + + echo "user id is ${_user_id}" + + _endpoint_url="/api/rbac/v1/users" + _method="GET" + _endpoint_url="${_endpoint_url}/${_user_id}" + if [[ _debug = true ]]; then _output="-v"; else _output="-s"; fi + + echo "endpoint is ${_endpoint_url}" + + # Get group by name + user=$(curl ${_output} -X ${_method} --user ${_user_credentials} ${_controller_url}{$_endpoint_url} ${_proxy_details}) + + echo "${user}" + +} + diff --git a/modules/rbac/create_license_rules.sh b/modules/rbac/create_license_rules.sh new file mode 100755 index 0000000..47becaf --- /dev/null +++ b/modules/rbac/create_license_rules.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +source ./modules/rbac/restui_auth.sh +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/rbac/restui_license_rules.sh # func_restui_create_license_rules + +_controller_url=${1} # hostname + /controller +_user_credentials=${2} # ${username}:${password} +_proxy_details=${3} +_application_name=${4} +_debug=${5} + +_arg_rbac_license_rule_name=${6} + +echo "| Create auth header and cookie." + +_token_header=$(func_restui_get_cookie "${_controller_url}" "${_user_credentials}" "${_proxy_details}") + +# todo debug mode? +#if [ _debug = true ]; then echo "appd token value is: ${_token_header}"; fi + +echo "| Creating license rule." +# create role +_create_license_rule_response=$(func_restui_create_license_rules "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_application_name}" "${_debug}" "${_token_header}" "${_arg_rbac_license_rule_name}") + +echo "${_create_license_rule_response}" + +echo "Done" diff --git a/modules/rbac/create_role_with_app_edit_and_attach_to_saml.sh b/modules/rbac/create_role_with_app_edit_and_attach_to_saml.sh new file mode 100755 index 0000000..8724912 --- /dev/null +++ b/modules/rbac/create_role_with_app_edit_and_attach_to_saml.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +source ./modules/rbac/api_roles.sh +source ./modules/rbac/api_users.sh +source ./modules/rbac/api_groups.sh + +source ./modules/rbac/restui_auth.sh +source ./modules/rbac/restui_roles.sh +source ./modules/rbac/restui_saml.sh + +source ./modules/common/http_check.sh # func_check_http_status + +_controller_url=${1} # hostname + /controller +_user_credentials=${2} # ${username}:${password} +_proxy_details=${3} +_application_name=${4} +_debug=${5} + +_role_name=${6} +_role_description=${7} + +_saml_group_name=${8} + +if [ -z "${_role_name// }" ]; then + func_check_http_status 404 "Role name not provided. Unable to create it without this value." + exit 1 +fi + +echo "| Create auth header and cookie." + +_token_header=$(func_restui_get_cookie "${_controller_url}" "${_user_credentials}" "${_proxy_details}") + +if [ _debug = true ]; then echo "appd token value is: ${_token_header}"; fi + +echo "| Create role '${_role_name}' with application permissions." +# create role +_role_with_permissions_response=$(func_restui_create_role_with_default_view_and_view_edit_app_permissions "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_application_name}" "${_debug}" "${_token_header}" "${_role_name}" "${_role_description}") + +sleep 5 # creating role takes some time, wait before going to fetch it + +echo "| Check if role created successfully." +_expected_response='"id" :' # returns id with space before : on success +func_check_http_response "\{$_role_with_permissions_response}" "${_expected_response}" + +echo "| Get role by id." +# get created role by name +_get_role_response=$(func_get_role_by_name "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_application_name}" "${_debug}" "${_role_name}") + +_expected_response='"id":' # returns id on success +func_check_http_response "\{$_get_role_response}" "${_expected_response}" + +# get role ID from response +_role_id=$(jq -r '.id' <<< $_get_role_response) + +sleep 1 + +# role ids have to be existing ones for saml update to be successfully performed (although 200 is returned in any case) +# Note: when multiple: e.g. role_ids="28,16" - no space! +if [ -z "${_role_id// }" ]; then + func_check_http_status 404 "Role '${_role_name}' ID not found. Unable to add its identifier to SAML group." + exit 1 +fi + +## SAML group +if [ -z "${_saml_group_name// }" ]; then + func_check_http_status 404 "SAML group name cannot be empty." + exit 1 +fi + +echo "| Attach role to SAML Group." +# create saml group +_saml_response=$(func_restui_update_saml_configuration "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_debug}" "${_token_header}" "${_role_id}" "${_saml_group_name}") + +echo "|| Role '${_role_name}' added to SAML group '${_saml_group_name}' successfully." \ No newline at end of file diff --git a/modules/rbac/restui_applications.sh b/modules/rbac/restui_applications.sh new file mode 100755 index 0000000..493e0ba --- /dev/null +++ b/modules/rbac/restui_applications.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source ./modules/common/application.sh #func_get_application_id + +function func_restui_get_application_guid() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + local _application_name=${4} + # no application name needed + local _debug=${5} + + local X_CSRF_TOKEN_HEADER=${6} + + _endpoint_url="/restui/licenseRule/getAllApplications" + _method="GET" + + allApplications=$(curl -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -X ${_method} "${_controller_url}${_endpoint_url}" ${_proxy_details}) + + # Select by name + applicationObject=$(jq --arg appName "$_application_name" '.[] | select(.name == $appName)' <<<$allApplications) + + if [ "$applicationObject" = "" ]; then + echo "" + exit 0 + fi + + appGuid=$(jq '.objectReference.id' <<<$applicationObject) + + echo "${appGuid}" + +} + diff --git a/modules/rbac/restui_auth.sh b/modules/rbac/restui_auth.sh new file mode 100755 index 0000000..0b92017 --- /dev/null +++ b/modules/rbac/restui_auth.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +function func_restui_get_cookie() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + response=$(curl -i -s -c cookie.appd --user ${_user_credentials} -X GET ${_controller_url}/auth?action=login ${_proxy_details}) + X_CSRF_TOKEN="$(grep X-CSRF-TOKEN cookie.appd|rev|cut -d$'\t' -f1|rev)" + X_CSRF_TOKEN_HEADER="`if [ -n "$X_CSRF_TOKEN" ]; then echo "X-CSRF-TOKEN:$X_CSRF_TOKEN"; else echo ''; fi`" + + echo "${X_CSRF_TOKEN_HEADER}" # echo header value only (to be used by other functions) +} + diff --git a/modules/rbac/restui_license_rules.sh b/modules/rbac/restui_license_rules.sh new file mode 100755 index 0000000..3b8dd3c --- /dev/null +++ b/modules/rbac/restui_license_rules.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/common/logging.sh # func_log_error_to_file +source ./modules/rbac/restui_applications.sh # func_restui_get_application_guid + +function func_restui_get_license_rules() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + local _application_name=${4} + local _debug=${5} + + local X_CSRF_TOKEN_HEADER=${6} + + if [[ _debug = true ]]; then echo ">> func_restui_get_roles"; fi + + _endpoint_url="/restui/licenseRule/getAllRulesSummary" + _method="GET" + + licenseRulesSummary=$(curl -v -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -X ${_method} "${_controller_url}${_endpoint_url}") + + echo "${licenseRulesSummary}" +} + +function func_restui_create_license_rules() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + local _application_name=${4} + local _debug=${5} + + local X_CSRF_TOKEN_HEADER=${6} + + local _license_rule_name=${7} + + #if [[ _debug = true ]]; then echo ">> func_restui_create_role_with_default_view_and_view_edit_app_permissions"; fi + + dt=$(date '+%Y-%m-%d_%H-%M-%S') + + _rule_name_placeholder="" + _rule_id_placeholder="" + _rule_key_placeholder="" + _application_name_placeholder="" + + _files_directory="./rbac/restui_license_rules_files" + + _uploaded_path="${_files_directory}/uploaded" + _payload_path="${_uploaded_path}/payload-${dt}.json" + + _payload_header="Content-Type: application/json; charset=utf8" + + _rbac_rnd=$((1 + $RANDOM % 1000)) + + itt=1 + + # prepare payload + for _json_file in $_files_directory/*.json; do + + _file_name="$(basename -- $_json_file)" + + # Check if folder contains files + [ -f "$_json_file" ] || func_check_http_status 404 "No files found in directory: '"$_files_directory"'. Aborting..." + + _tmp_updated_file_path="${_uploaded_path}/tmp-${_file_name}-${dt}" + _tmp_updated_file_path_final="${_uploaded_path}/tmp-fin-${_file_name}-${dt}" + + # generate for each file found in directory + _rule_name="${_license_rule_name}-${_rbac_rnd}-${itt}" + _rule_id=$(uuidgen) + _rule_key=$(uuidgen) + + echo -e "|| Processing '${_file_name}' file, creating license rule '${_rule_name}'." + + # replacing license rule name + if grep -q $_rule_name_placeholder ${_json_file}; then + touch "${_tmp_updated_file_path}" + sed -e "s/${_rule_name_placeholder}/${_rule_name}/g" "${_json_file}" > "${_tmp_updated_file_path}" + else + echo -e "|| WARNING Placeholder value '$_rule_name_placeholder' not found in '${_file_name}'. Value not replaced." + copying=$(cp "${_json_file}" "${_tmp_updated_file_path}") + fi + + # replacing application name (if exists) + if grep -q $_application_name_placeholder ${_json_file}; then + # get application guid + application_guid=$(func_restui_get_application_guid "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_application_name}" "${_debug}" "${_token_header}") + + application_guid=$(echo $application_guid | tr -d '"') + + if [[ ! -z "${application_guid// }" ]]; then + sed -e "s/${_application_name_placeholder}/${application_guid}/g" "${_tmp_updated_file_path}" > "${_tmp_updated_file_path_final}" + else + echo -e "|| WARNING GUID value for placeholder '$_application_name_placeholder' not found. Value not replaced." + _tmp_updated_file_path_final="${_tmp_updated_file_path}" + fi + else + echo -e "|| WARNING Placeholder value '$_application_name_placeholder' not found in '${_file_name}'. Value not replaced." + _tmp_updated_file_path_final="${_tmp_updated_file_path}" + fi + + # replace rule id and key + touch "${_payload_path}" + sed -e "s/${_rule_id_placeholder}/${_rule_id}/g" -e "s/${_rule_key_placeholder}/${_rule_key}/g" "${_tmp_updated_file_path_final}" > "${_payload_path}" + + _endpoint_url="/restui/licenseRule/create" + _method="POST" + + response=$(curl -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -H "${_payload_header}" -X ${_method} --data "@${_payload_path}" "${_controller_url}${_endpoint_url}") + + #echo "RESPONSE >>>>> $response" + + echo "| Check if rule created successfully." + _expected_response='"id" :' # returns id with space before : on success + func_check_http_response "\{$response}" "${_expected_response}" + + license_name=$(jq '.name' <<<$response) + + echo -e "|License rule '${license_name}' created. \n" + + # remove temporary files, save only final payload backup + rm ${_uploaded_path}/tmp-* + + _rule_name="${_license_rule_name}" + itt=$((itt + 1)) + + done + + + +} + + diff --git a/modules/rbac/restui_roles.sh b/modules/rbac/restui_roles.sh new file mode 100755 index 0000000..4dd60a0 --- /dev/null +++ b/modules/rbac/restui_roles.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +source ./modules/common/http_check.sh # func_check_http_status +source ./modules/common/application.sh #func_get_application_id + +function func_restui_get_roles() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + local _application_name=${4} + local _debug=${5} + + local X_CSRF_TOKEN_HEADER=${6} + + if [[ _debug = true ]]; then echo ">> func_restui_get_roles"; fi + + _endpoint_url="/restui/accountRoleAdministrationUiService/accountRoleSummaries" + _method="GET" + + roleSummaries=$(curl -v -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -X ${_method} "${_controller_url}${_endpoint_url}") + + echo "${roleSummaries}" +} + +function func_restui_create_role_with_default_view_and_view_edit_app_permissions() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + + local _application_name=${4} + local _debug=${5} + + local X_CSRF_TOKEN_HEADER=${6} + + local _role_name=${7} + local _role_description=${8} + + echo "||Creating role '${_role_name}'..." + + #if [[ _debug = true ]]; then echo ">> func_restui_create_role_with_default_view_and_view_edit_app_permissions"; fi + + dt=$(date '+%Y-%m-%d_%H-%M-%S') + + _application_id_placeholder="" + _overall_permissions_placeholder="" + _application_permissions_placeholder="" + _role_name_placeholder="" + _role_description_placeholder="" + + _files_directory="./rbac/restui_role_files" + + _application_permissions_path="${_files_directory}/permissions_view_edit_app.json" + _overall_permissions_path="${_files_directory}/permissions_view.json" + _permissions_base_path="${_files_directory}/permissions_base.json" + + _uploaded_path="${_files_directory}/uploaded" + + _payload_path="${_uploaded_path}/payload-${dt}.json" + _payload_header="Content-Type: application/json; charset=utf8" + + application_permission_final="${_uploaded_path}/tmp-permissions_view_edit_app.json-${dt}" + + # get application id + _app_id=$(func_get_application_id "${_controller_url}" "${_user_credentials}" "${_application_name}" "${_proxy_details}") + + # prepare payload + for _json_file in ${_application_permissions_path}; do + + _file_name="$(basename -- $_json_file)" + + echo -e "Processing '${_file_name}' json file, setting permissions for '${_application_name}' application." + + # replacing application id + if grep -q $_application_id_placeholder ${_json_file}; then + sed -e "s/${_application_id_placeholder}/${_app_id}/g" "${_json_file}" > "${application_permission_final}" + else + echo -e "WARNING Placeholder value '$_application_id_placeholder' not found in '${_file_name}'. " + fi + done + + for _json_file in ${_permissions_base_path}; do + + _file_name="$(basename -- $_json_file)" + + _updated_file_path="${_uploaded_path}/tmp-${_file_name}-${dt}" + _tmp_updated_file_path="${_uploaded_path}/tmp-edited-${_file_name}-${dt}" + + echo -e "Processing '${_file_name}' json file, setting global permissions." + + # set overall permissions + if grep -q $_overall_permissions_placeholder ${_json_file}; then + # replace newline with space + value=$(sed -e ':a' -e 'N;$!ba' -e 's/\n/ /g' ${_overall_permissions_path}) + sed -e "s/${_overall_permissions_placeholder}/${value}/g" "${_json_file}" > "${_tmp_updated_file_path}" + else + echo -e "WARNING Placeholder value '$_overall_permissions_placeholder' not found in '${_file_name}'. " + fi + + # set application-specific permissions + if grep -q $_application_permissions_placeholder ${_tmp_updated_file_path}; then + # replace newline with space + value=$(sed -e ':a' -e 'N;$!ba' -e 's/\n/ /g' ${application_permission_final}) + sed -e "s/${_application_permissions_placeholder}/${value}/" "${_tmp_updated_file_path}" > "${_updated_file_path}" + else + echo -e "WARNING Placeholder value '$_application_permissions_placeholder' not found in '${_file_name}'. " + fi + + done + + # replace role name and description + sed -e "s/${_role_name_placeholder}/${_role_name}/g" -e "s/${_role_description_placeholder}/${_role_description}/g" "${_updated_file_path}" > "${_payload_path}" + + _endpoint_url="/restui/accountRoleAdministrationUiService/accountRoles/create" + _method="POST" + + response=$(curl -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -H "${_payload_header}" -X ${_method} --data "@${_payload_path}" "${_controller_url}${_endpoint_url}") + + # remove temporary files, save only final payload backup + rm ${_uploaded_path}/tmp-* + + echo "${response}" + +} + + diff --git a/modules/rbac/restui_saml.sh b/modules/rbac/restui_saml.sh new file mode 100755 index 0000000..ee5b1f7 --- /dev/null +++ b/modules/rbac/restui_saml.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +source ./modules/common/application.sh #func_get_application_id + +function func_restui_get_saml_configuration() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + # no application name needed + local _debug=${4} + + local X_CSRF_TOKEN_HEADER=${5} + + if [[ _debug = true ]]; then echo ">> func_restui_get_saml_configuration"; fi + + _endpoint_url="/restui/accountAdmin/getSAMLConfiguration" + _method="GET" + + response=$(curl -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -X ${_method} "${_controller_url}${_endpoint_url}" ${_proxy_details}) + + echo "${response}" + +} + +function func_restui_update_saml_configuration() { + local _controller_url=${1} # hostname + /controller + local _user_credentials=${2} # ${username}:${password} + local _proxy_details=${3} + # no application name needed + local _debug=${4} + + local X_CSRF_TOKEN_HEADER=${5} + + local _role_ids=${6} + local _saml_group_name=${7} + + _payload_header="Content-Type: application/json; charset=utf8" + + dt=$(date '+%Y-%m-%d_%H-%M-%S') + + _files_directory="./rbac/restui_saml_files" + _uploaded_path="${_files_directory}/uploaded" + _payload_backup_path="${_uploaded_path}/payload-${dt}.json" + + #todo check if single integer or comma-separated IDs + + # get current configuration + _current_saml_config=$(func_restui_get_saml_configuration "${_controller_url}" "${_user_credentials}" "${_proxy_details}" "${_debug}" "${X_CSRF_TOKEN_HEADER}") + + if [[ _debug = true ]]; then echo "current saml config is: ${_current_saml_config}"; fi + + # add new group + _with_group=$(jq '.samlRoles += ["'"$_saml_group_name"'"]' <<< $_current_saml_config) + + _payload_with_group_and_roles=$(jq --arg new "$_role_ids" '.accountRoles += ['[$_role_ids]']' <<< $_with_group) + + if [[ _debug = true ]]; then echo "updated saml config is: ${_payload_with_group_and_roles}"; fi + + # number of roles and groups count control? + + _endpoint_url="/restui/accountAdmin/updateSAMLConfiguration" + _method="POST" + + response=$(curl -s -b cookie.appd -H "$X_CSRF_TOKEN_HEADER" -H "${_payload_header}" -X ${_method} -d "${_payload_with_group_and_roles}" "${_controller_url}${_endpoint_url}") + + echo "${response}" > ${_payload_backup_path} +} + + diff --git a/rbac/restui_license_rules_files/payload_all.json b/rbac/restui_license_rules_files/payload_all.json new file mode 100644 index 0000000..b288f22 --- /dev/null +++ b/rbac/restui_license_rules_files/payload_all.json @@ -0,0 +1,37 @@ +{ + "id": "", + "account_id": "", + "name": "", + "access_key": "", + "constraints": [ + { + "entity_type_id": "com.appdynamics.modules.apm.topology.impl.persistenceapi.model.ApplicationEntity", + "constraint_type": "ALLOW_ALL", + "match_conditions": [] + }, + { + "entity_type_id": "com.appdynamics.modules.apm.topology.impl.persistenceapi.model.MachineEntity", + "constraint_type": "ALLOW_ALL", + "match_conditions": [] + } + ], + "entitlements": [ + { + "license_module_type": "APM", + "number_of_licenses": 0 + }, + { + "license_module_type": "MACHINE_AGENT", + "number_of_licenses": 0 + }, + { + "license_module_type": "SIM_MACHINE_AGENT", + "number_of_licenses": 0 + }, + { + "license_module_type": "NETVIZ", + "number_of_licenses": 0 + } + ], + "enabled": true +} \ No newline at end of file diff --git a/rbac/restui_license_rules_files/payload_app.json b/rbac/restui_license_rules_files/payload_app.json new file mode 100644 index 0000000..1547047 --- /dev/null +++ b/rbac/restui_license_rules_files/payload_app.json @@ -0,0 +1,43 @@ +{ + "id": "", + "account_id": "", + "name": "", + "access_key": "", + "constraints": [ + { + "entity_type_id": "com.appdynamics.modules.apm.topology.impl.persistenceapi.model.ApplicationEntity", + "constraint_type": "ALLOW_SELECTED", + "match_conditions": [ + { + "match_type": "EQUALS", + "attribute_type": "ID", + "match_string": "" + } + ] + }, + { + "entity_type_id": "com.appdynamics.modules.apm.topology.impl.persistenceapi.model.MachineEntity", + "constraint_type": "ALLOW_ALL", + "match_conditions": [] + } + ], + "entitlements": [ + { + "license_module_type": "APM", + "number_of_licenses": 0 + }, + { + "license_module_type": "MACHINE_AGENT", + "number_of_licenses": 0 + }, + { + "license_module_type": "SIM_MACHINE_AGENT", + "number_of_licenses": 0 + }, + { + "license_module_type": "NETVIZ", + "number_of_licenses": 0 + } + ], + "enabled": true +} \ No newline at end of file diff --git a/rbac/restui_license_rules_files/uploaded/.gitkeep b/rbac/restui_license_rules_files/uploaded/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rbac/restui_role_files/permissions_base.json b/rbac/restui_role_files/permissions_base.json new file mode 100644 index 0000000..b5eeb08 --- /dev/null +++ b/rbac/restui_role_files/permissions_base.json @@ -0,0 +1,9 @@ +{ + "permissions": [ + + , + + ], + "name": "", + "description": "" +} \ No newline at end of file diff --git a/rbac/restui_role_files/permissions_view.json b/rbac/restui_role_files/permissions_view.json new file mode 100644 index 0000000..d5b14f2 --- /dev/null +++ b/rbac/restui_role_files/permissions_view.json @@ -0,0 +1,240 @@ +{ + "action": "VIEW", + "allowed": true, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "DELETE", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_TRANSACTION_DETECTION", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BACKEND_DETECTION", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_ERROR_DETECTION", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_DIAGNOSTIC_DATA_COLLECTORS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_CALLGRAPH_SETTINGS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_JMX", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_MEMORY_MONITORING", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_EUM", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_INFO_POINTS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_POLICIES", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_EVENT_REACTOR", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_ACTIONS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BUSINESS_TRANSACTIONS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BASELINES", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_SQL_BIND_VARIABLES", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_AGENT_PROPERTIES", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_SERVICE_ENDPOINTS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "ENABLE_DEVELOPMENT_MODE", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "MANAGE_CUSTOM_DASHBOARD_TEMPLATES", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_SIM", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_AGENT_OPERATIONS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_TRIGGER_DIAGNOSTIC_SESSION", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "ENABLE_JMX_OPERATIONS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "VIEW_SENSITIVE_DATA", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "VIEW_SIM", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "NETVIZ_AGENT_PCAP_TRIGGER", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "ACI_APIC_TROUBLESHOOTING", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +}, +{ + "action": "CREATE_EVENTS", + "allowed": false, + "affectedEntity": { + "entityId": 0, + "entityType": "APPLICATION" + } +} diff --git a/rbac/restui_role_files/permissions_view_edit_app.json b/rbac/restui_role_files/permissions_view_edit_app.json new file mode 100644 index 0000000..b6c7670 --- /dev/null +++ b/rbac/restui_role_files/permissions_view_edit_app.json @@ -0,0 +1,224 @@ +{ + "action": "VIEW", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "DELETE", + "allowed": false, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_TRANSACTION_DETECTION", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BACKEND_DETECTION", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_ERROR_DETECTION", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_DIAGNOSTIC_DATA_COLLECTORS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_CALLGRAPH_SETTINGS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_JMX", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_MEMORY_MONITORING", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_EUM", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_INFO_POINTS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_POLICIES", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_EVENT_REACTOR", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_ACTIONS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BUSINESS_TRANSACTIONS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_BASELINES", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_SQL_BIND_VARIABLES", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_AGENT_PROPERTIES", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_AGENT_OPERATIONS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "ENABLE_JMX_OPERATIONS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_SERVICE_ENDPOINTS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "ENABLE_DEVELOPMENT_MODE", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "MANAGE_CUSTOM_DASHBOARD_TEMPLATES", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CONFIG_TRIGGER_DIAGNOSTIC_SESSION", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "NETVIZ_AGENT_PCAP_TRIGGER", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "ACI_APIC_TROUBLESHOOTING", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "VIEW_SENSITIVE_DATA", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +}, +{ + "action": "CREATE_EVENTS", + "allowed": true, + "affectedEntity": { + "entityId": , + "entityType": "APPLICATION" + } +} diff --git a/rbac/restui_role_files/uploaded/.gitkeep b/rbac/restui_role_files/uploaded/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/rbac/restui_saml_files/uploaded/.gitkeep b/rbac/restui_saml_files/uploaded/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/start.sh b/start.sh index 235343f..0c5f373 100755 --- a/start.sh +++ b/start.sh @@ -28,7 +28,6 @@ begins_with_short_option() # THE DEFAULTS INITIALIZATION - OPTIONALS _arg_use_encoded_credentials=false - _arg_controller_host= _arg_controller_port=8090 _arg_use_https=false @@ -67,6 +66,15 @@ _arg_include_database=false _arg_database_name= _arg_include_sim=false +_valid_rbac_actions=("role-saml" "license-rule") # array of valid rbac actions e.g. ("role" "role-saml" "saml") + +_arg_rbac_only=false +_arg_rbac_action="role-saml" # the only action for now in rbac module is "role-saml" +_arg_rbac_role_name= +_arg_rbac_role_description= +_arg_rbac_saml_group_name= +_arg_rbac_license_rule_name= + _arg_debug=false _arg_controller_port_explicitly_set=false @@ -85,6 +93,8 @@ _arg_upload_default_dashboard_explicitly_set=false _arg_upload_custom_dashboard_explicitly_set=false _arg_health_rules_only_explicitly_set=false _arg_health_rules_overwrite_explicitly_set=false +_arg_rbac_only_explicitly_set=false +_arg_rbac_action_explicitly_set=false print_help() @@ -143,6 +153,14 @@ print_help() printf '\t%s\n' "-d, --database-name: mandatory if --include-database set to true (no default)" printf '\t%s\n' "-s, --include-sim, --no-include-sim: include server visibility (${_arg_include_sim} by default)" + printf '%s\n' "Role-Based Access Control (RBAC) options:" + printf '\t%s\n' "--rbac-only, --no-rbac-only: configure RBAC (${_arg_rbac_only} by default)" + printf '\t%s\n' "--rbac-action: RBAC action to be performed ('${_arg_rbac_action}' by default)" + printf '\t%s\n' "--rbac-role-name: RBAC role name (auto-generated by default)" + printf '\t%s\n' "--rbac-role-description: RBAC role description, not mandatory (no default)" + printf '\t%s\n' "--rbac-saml-group-name: RBAC SAML group name (auto-generated by default)" + printf '\t%s\n' "--rbac-license-rule-name: License rule name (auto-generated by default)" + printf '%s\n' "Help options:" printf '\t%s\n' "-h, --help: Prints help" printf '\t%s\n' "--debug, --no-debug: Run in debug mode (${_arg_debug} by default)" @@ -396,6 +414,52 @@ parse_commandline() _arg_upload_default_dashboard_explicitly_set=true test "${1:0:5}" = "--no-" && _arg_upload_default_dashboard=false ;; + --no-rbac-only|--rbac-only) + _arg_rbac_only=true + _arg_rbac_only_explicitly_set=true + test "${1:0:5}" = "--no-" && _arg_rbac_only=false + ;; + --rbac-action) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_rbac_action="$2" + shift + ;; + --rbac-action=*) + _arg_rbac_action_explicitly_set=true + _arg_rbac_action="${_key##--rbac-action=}" + ;; + --rbac-role-name) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_rbac_role_name="$2" + shift + ;; + --rbac-role-name=*) + _arg_rbac_role_name="${_key##--rbac-role-name=}" + ;; + --rbac-role-description) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_rbac_role_description="$2" + shift + ;; + --rbac-role-description=*) + _arg_rbac_role_description="${_key##--rbac-role-description=}" + ;; + --rbac-saml-group-name) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_rbac_saml_group_name="$2" + shift + ;; + --rbac-saml-group-name=*) + _arg_rbac_saml_group_name="${_key##--rbac-saml-group-name=}" + ;; + --rbac-license-rule-name) + test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 + _arg_rbac_license_rule_name="$2" + shift + ;; + --rbac-license-rule-name=*) + _arg_rbac_license_rule_name="${_key##--rbac-license-rule-name=}" + ;; -h|--help) print_help exit 0 @@ -497,6 +561,10 @@ handle_expected_values_for_args() if ([ ! $_arg_upload_default_dashboard = false ] && [ ! $_arg_upload_default_dashboard = true ] ); then _PRINT_HELP=no die "FATAL ERROR: --upload-default-dashboard value \"${_arg_upload_default_dashboard}\" not recognized" 1 fi + + if ([ ! $_arg_rbac_only = false ] && [ ! $_arg_rbac_only = true ] ); then + _PRINT_HELP=no die "FATAL ERROR: _arg_rbac_only value \"${_arg_rbac_only}\" not recognized" 1 + fi } ### 1 SET PARAMETER VALUES ### @@ -622,6 +690,26 @@ if ([ $_arg_upload_default_dashboard_explicitly_set = false ] && [ ! -z "${CMA_U _arg_upload_default_dashboard=${CMA_UPLOAD_DEFAULT_DASHBOARD} fi +# RBAC +if ([ $_arg_rbac_only_explicitly_set = false ] && [ ! -z "${CMA_RBAC_ONLY// }" ]); then + _arg_rbac_only=${CMA_RBAC_ONLY} +fi +if ([ $_arg_rbac_action_explicitly_set = false ] && [ ! -z "${CMA_RBAC_ACTION// }" ]); then + _arg_rbac_action=${CMA_RBAC_ACTION} +fi +if ([ -z "${_arg_rbac_role_name// }" ] && [ ! -z "${CMA_RBAC_ROLE_NAME// }" ]); then + _arg_rbac_role_name=${CMA_RBAC_ROLE_NAME} +fi +if ([ -z "${_arg_rbac_role_description// }" ] && [ ! -z "${CMA_RBAC_ROLE_DESCRIPTION// }" ]); then + _arg_rbac_role_description=${CMA_RBAC_ROLE_DESCRIPTION} +fi +if ([ -z "${_arg_rbac_saml_group_name// }" ] && [ ! -z "${CMA_RBAC_SAML_GROUP_NAME// }" ]); then + _arg_rbac_saml_group_name=${CMA_RBAC_SAML_GROUP_NAME} +fi +if ([ -z "${_arg_rbac_license_rule_name// }" ] && [ ! -z "${CMA_RBAC_LICENSE_RULE_NAME// }" ]); then + _arg_rbac_license_rule_name=${CMA_RBAC_LICENSE_RULE_NAME} +fi + # 1.3 If value not set replace with configuration file values conf_file="config.json" @@ -741,6 +829,26 @@ if ([[ $_arg_upload_default_dashboard_explicitly_set = false ]] && [ -z "${CMA_U _arg_upload_default_dashboard=$(jq -r '.configuration[].upload_default_dashboard' <${conf_file}) fi +# RBAC +if ([[ $_arg_rbac_only_explicitly_set = false ]] && [ -z "${CMA_RBAC_ONLY// }" ]); then + _arg_rbac_only=$(jq -r '.rbac[].rbac_only' <${conf_file}) +fi +if ([[ $_arg_rbac_action_explicitly_set = false ]] && [ -z "${CMA_RBAC_ACTION// }" ]); then + _arg_rbac_action=$(jq -r '.rbac[].rbac_action' <${conf_file}) +fi +if [[ -z "${_arg_rbac_role_name// }" ]]; then + _arg_rbac_role_name=$(jq -r '.rbac[].rbac_role_name' <${conf_file}) +fi +if [[ -z "${_arg_rbac_role_description// }" ]]; then + _arg_rbac_role_description=$(jq -r '.rbac[].rbac_role_description' <${conf_file}) +fi +if [[ -z "${_arg_rbac_saml_group_name// }" ]]; then + _arg_rbac_saml_group_name=$(jq -r '.rbac[].rbac_saml_group_name' <${conf_file}) +fi +if [[ -z "${_arg_rbac_license_rule_name// }" ]]; then + _arg_rbac_license_rule_name=$(jq -r '.rbac[].rbac_license_rule_name' <${conf_file}) +fi + ### 2 VALIDATE ### # 2.1 Check if values are in expected ranges @@ -795,6 +903,13 @@ if [ $_arg_debug = true ]; then echo "Value of --upload-custom-dashboard: $_arg_upload_custom_dashboard" echo "Value of --upload-default-dashboard: $_arg_upload_default_dashboard" + + echo "Value of --rbac-only: $_arg_rbac_only" + echo "Value of --rbac-action: $_arg_rbac_action" + echo "Value of --rbac-role-name: $_arg_rbac_role_name" + echo "Value of --rbac-role-description: $_arg_rbac_role_description" + echo "Value of --rbac-saml-group-name: $_arg_rbac_saml_group_name" + echo "Value of --rbac-license-rule-name: $_arg_rbac_license_rule_name" fi @@ -868,11 +983,45 @@ if [ $_arg_suppress_action = true ]; then # set to current datetime if empty # UTC / GMT _arg_suppress_start=$(date -u +%FT%T+0000) + echo "DEF|Default action suppression start time created '${_arg_suppress_start}'" fi if [ -z "${_arg_suppress_duration// }" ]; then # set to one hour if empty _arg_suppress_duration=60 + echo "DEF|Default action suppression duration created '${_arg_suppress_duration}'" + fi +fi + +# 3.6 Prepare RBAC +if [ $_arg_rbac_only = true ]; then + # validate action (check if valid option) + if [[ ! " ${_valid_rbac_actions[@]} " =~ " ${_arg_rbac_action} " ]]; then + # whatever you want to do when array doesn't contain value + _PRINT_HELP=no die "FATAL ERROR: --rbac-action value \"${_arg_rbac_action}\" not recognized" 1 + fi + + _rbac_prefix="cma" + _rbac_rnd=$((1 + $RANDOM % 1000)) + + # default saml group name + if [ -z "${_arg_rbac_saml_group_name// }" ]; then + # if empty + _arg_rbac_saml_group_name="${_rbac_prefix}_group_${_arg_application_name}_${_rbac_rnd}" + echo "DEF|Default RBAC SAML group name created '${_arg_rbac_saml_group_name}'" + fi + + # default role name + if [ -z "${_arg_rbac_role_name// }" ]; then + # if empty + _arg_rbac_role_name="${_rbac_prefix}_role_${_arg_application_name}_${_rbac_rnd}" + echo "DEF|Default RBAC role name created '${_arg_rbac_role_name}'" fi + + if [ -z "${_arg_rbac_license_rule_name// }" ]; then + _arg_rbac_license_rule_name="${_rbac_prefix}_rule" # more than one rule can be uploaded during a single run, rand added in module + echo "DEF|License rule name created '${_arg_rbac_license_rule_name}'" + fi + fi ## VALIDATIONS [prereqs] @@ -902,6 +1051,19 @@ case $ec in 1) printf '%s\n' "Command exited with non-zero code"; exit 1;; esac +### RBAC ### +if ([[ $_arg_rbac_only = true ]] && [ $_arg_rbac_action = "role-saml" ]); then + echo -e "\n> Running 'RBAC' module" + echo -e ">> Action 'Create Role and SAML Attach'\n" + ./modules/rbac/create_role_with_app_edit_and_attach_to_saml.sh "$_arg_controller_url" "$_arg_user_credentials" "$_arg_proxy_details" "$_arg_application_name" "$_arg_debug" "$_arg_rbac_role_name" "$_arg_rbac_role_description" "$_arg_rbac_saml_group_name" +fi + +if ([[ $_arg_rbac_only = true ]] && [ $_arg_rbac_action = "license-rule" ]); then + echo -e "\n> Running 'RBAC' module" + echo -e ">> Action 'Create License Rule'\n" + ./modules/rbac/create_license_rules.sh "$_arg_controller_url" "$_arg_user_credentials" "$_arg_proxy_details" "$_arg_application_name" "$_arg_debug" "$_arg_rbac_license_rule_name" +fi + ### 4 ACTION SUPRESSION ### if [ $_arg_suppress_action = true ]; then echo -e "\n> Running 'Action Supression' module"