diff --git a/ise/ISE-bash-scripts/.gitignore b/ise/ISE-bash-scripts/.gitignore new file mode 100644 index 0000000..3d10c82 --- /dev/null +++ b/ise/ISE-bash-scripts/.gitignore @@ -0,0 +1,2 @@ +*.tar.gz + diff --git a/ise/ISE-bash-scripts/README.md b/ise/ISE-bash-scripts/README.md new file mode 100644 index 0000000..3d2b303 --- /dev/null +++ b/ise/ISE-bash-scripts/README.md @@ -0,0 +1,19 @@ +# ISE Utility Bash Scripts + +Currently these set of scripts are able to: +- Login to ISE +- Logout of ISE +- Enable/Disable ERS API +- Create new OCSP Profile +- Disable admin password requirements such as expiration and complexity + +## Usage +1. Change `HOSTNAME` in `login.bash` to the IP address/FQDN of your ISE server. +2. Read the script to understand what it is doing and modify any variables that you need to. + 1. For example, `create_new_ocsp_profile.bash` requires you to modify the following: + - CRUD="Create" + - OCSP_PRIMARY_URL="[2001:420:27ff:fff9::7]:5000" + - OCSP_SERVICE_NAME="ggg" + - SELECTED_ITEM_NAME="ggg" +2. Execute any of the scripts that you want to modify settings on. + diff --git a/ise/ISE-bash-scripts/create_new_ocsp_profile.bash b/ise/ISE-bash-scripts/create_new_ocsp_profile.bash new file mode 100755 index 0000000..cd93314 --- /dev/null +++ b/ise/ISE-bash-scripts/create_new_ocsp_profile.bash @@ -0,0 +1,23 @@ +#!/bin/bash + +source ./login.bash + +# Make OCSP request +echo -e "Updating OCSP Client Profile" +CRUD="Create" # This can be Create or Edit +OCSP_PRIMARY_URL="[2001:420:27ff:fff9::7]:5000" +OCSP_SERVICE_NAME="ggg" +SELECTED_ITEM_NAME="ggg" # This one is needed when you edit an existing OCSP service +curl -k 'https://diorite.cisco.com/admin/ocspServicesAction.do' -X POST \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' \ + -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate, br, zstd' \ + -H '_QPH_: Y29tbWFuZD1zYXZl' -H 'Content-Type: application/x-www-form-urlencoded' \ + -H 'X-Requested-With: XMLHttpRequest, XMLHttpRequest' \ + -H "OWASP_CSRFTOKEN: ${CSRFTOKEN}" \ + -H 'Connection: keep-alive' \ + -H "Cookie: APPSESSIONID=${APPSESSIONID}; MNTLA_JWT_TOKEN=${JWT_TOKEN}" \ + --data-raw "crud=$CRUD&selectedItemName=$SELECTED_ITEM_NAME&ocspServicesStub.failoverToSecondary=false&ocspServicesStub.alwaysAccessPrimaryFirst=true&ocspServicesStub.primaryNonceExtensions=true&ocspServicesStub.primaryValidateResponseSignature=true&ocspServicesStub.secondaryNonceExtensions=true&ocspServicesStub.secondaryValidateResponseSignature=true&ocspServicesStub.selectedOCSPConfig=OCSP_RESPONDER&ocspServicesStub.enableNonceExtensionSupportAia=true&ocspServicesStub.validateResponseSignatureAia=true&ocspServicesStub.name=$OCSP_SERVICE_NAME&ocspServicesStub.description=&ocspServicesStub.primaryURL=$OCSP_PRIMARY_URL&primaryNonceExtensionsCB=on&primaryValidateResponseSignatureCB=on&ocspServicesStub.cacheTimeout=1440" 2>/dev/null | jq + +source ./logout.bash + diff --git a/ise/ISE-bash-scripts/disable_admin_annoyances.bash b/ise/ISE-bash-scripts/disable_admin_annoyances.bash new file mode 100755 index 0000000..3c7962e --- /dev/null +++ b/ise/ISE-bash-scripts/disable_admin_annoyances.bash @@ -0,0 +1,17 @@ +#!/bin/bash + +source ./login.bash + +# _QPC_ is a base64 encoded string that contains the CSRF token +QPC=$(printf "command=editAuthSubmit&OWASP_CSRFTOKEN=$CSRFTOKEN" | $BASE64 -w0) + +curl "https://$HOSTNAME/admin/adminAuthSettingsAction.do" --compressed --insecure -X POST \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8' \ + -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br, zstd' \ + -H 'Content-Type: multipart/form-data; boundary=---------------------------1799742068132450087154255035' \ + -H "Cookie: APPSESSIONID=$APPSESSIONID; _QPC_=$QPC; MNTLA_JWT_TOKEN=$JWT_TOKEN" \ + --data-binary $'-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordLengthTxt"\r\n\r\n4\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordNotUserCharsTxt"\r\n\r\n\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.isNewDictFile"\r\n\r\nfalse\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordHistoryTxt"\r\n\r\n3\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordReuse"\r\n\r\n15\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordDisableUserAccountTxt"\r\n\r\n45\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="adminAuthSettingsStub.passwordDisplayReminderTxt"\r\n\r\n30\r\n-----------------------------1799742068132450087154255035\r\nContent-Disposition: form-data; name="OWASP_CSRFTOKEN"\r\n\r\n""\r\n-----------------------------1799742068132450087154255035--\r\n' + +source ./logout.bash + diff --git a/ise/ISE-bash-scripts/enable_ers_api.bash b/ise/ISE-bash-scripts/enable_ers_api.bash new file mode 100755 index 0000000..b5730d9 --- /dev/null +++ b/ise/ISE-bash-scripts/enable_ers_api.bash @@ -0,0 +1,27 @@ +#!/bin/bash + +source ./login.bash + +# Make the API call to enable ERS API +ENABLE_ERS_API='true' +curl -k "https://$HOSTNAME/admin/ersSettingsAction.do" -X POST \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \ + -H 'Accept: */*' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate, br, zstd' \ + -H '_QPH_: Y29tbWFuZD1zdWJtaXRBUElTZXJ2aWNlU2V0dGluZ3M=' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H 'X-Requested-With: XMLHttpRequest, XMLHttpRequest' \ + -H "OWASP_CSRFTOKEN: $CSRFTOKEN" \ + -H "Origin: https://$HOSTNAME" \ + -H 'Connection: keep-alive' \ + -H 'Referer: https://diorite.cisco.com/admin/' \ + -H "Cookie: APPSESSIONID=$APPSESSIONID; MNTLA_JWT_TOKEN=$JWT_TOKEN" \ + -H 'Sec-Fetch-Dest: empty' \ + -H 'Sec-Fetch-Mode: cors' \ + -H 'Sec-Fetch-Site: same-origin' \ + -H 'Priority: u=0' \ + --data-raw "PAPEnabled=$ENABLE_ERS_API&OWASP_CSRFTOKEN=$CSRFTOKEN" 2>/dev/null | awk '{$1=$1};1' | awk '{printf "%s",$0} END {print ""}' | awk '{gsub(/'\''/, "\""); print}' | jq + +source ./logout.bash + diff --git a/ise/ISE-bash-scripts/execute_jenkins_job.bash b/ise/ISE-bash-scripts/execute_jenkins_job.bash new file mode 100755 index 0000000..3474010 --- /dev/null +++ b/ise/ISE-bash-scripts/execute_jenkins_job.bash @@ -0,0 +1,14 @@ +#!/bin/bash + +JOB_NAME=STO_Sparta_sysdevST02 +JOB_SCRIPT=ipv6_policy_set_radius_attributes.py +BRANCH_NAME=radius_ipv6_ise_1971 + +curl -k -X POST https://spotlight-jenkins.cisco.com/job/STO_Sparta/job/$JOB_NAME/buildWithParameters \ + --user iuser:11cdf2ceeab4fd7bd0e3d3bca18066ad2a \ + --data jobname=$JOB_SCRIPT \ + --data branch=$BRANCH_NAME \ + --data revert=true \ + --data revert_option=init/standalone \ + --data build=3.4.0.379 + diff --git a/ise/ISE-bash-scripts/login.bash b/ise/ISE-bash-scripts/login.bash new file mode 100755 index 0000000..56a3ee4 --- /dev/null +++ b/ise/ISE-bash-scripts/login.bash @@ -0,0 +1,74 @@ +#!/bin/bash + +HOSTNAME="sto-sparta-ise-3.cisco.com" +USERNAME="admin" +PASSWORD="Lab@12345" +APPSESSIONID=0 +CSRFTOKEN=0 +JWT_TOKEN=0 +QPC=0 + +GREP="grep" +BASE64="base64" +if [[ "$OSTYPE" == "darwin"* ]]; then + echo -e "Using g* tools because of course macOS" + GREP="ggrep" + BASE64="gbase64" +fi + +# Get the CSRF token and APPSESSIONID +echo -e "Getting CSRF token and initial APPSESSIONID" +output=$(curl -c - -k -L -s --compressed --request POST \ + --url https://$HOSTNAME/admin/JavaScriptServlet \ + --header 'Accept: */*' \ + --header 'Accept-Encoding: gzip, deflate, br, zstd' \ + --header 'Accept-Language: en-US,en;q=0.5' \ + --header 'Connection: keep-alive' \ + --header 'Content-Length: 0' \ + --header 'DNT: 1' \ + --header 'FETCH-CSRF-TOKEN: 1' \ + --header 'Origin: CWILLIA5-M-WJ2C' \ + --header 'Sec-Fetch-Dest: empty' \ + --header 'Sec-GPC: 1' \ + --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' 2>/dev/null ) + +CSRFTOKEN=$(echo $output | $GREP -oP '(?<=OWASP_CSRFTOKEN:)[^#]*') +APPSESSIONID=$(echo $output | awk '{print $NF}') +echo -e "CSRFTOKEN: $CSRFTOKEN" +echo -e "APPSESSIONID: $APPSESSIONID" + +# Get the JWT token +echo -e "Logging in, getting JWT token and updating APPSESSIONID" +output=$(curl -k -c - --request POST \ + --cookie "APPSESSIONID=$APPSESSIONID" \ + --url https://$HOSTNAME/admin/LoginAction.do \ + --header 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ + --header 'Accept-Encoding: gzip, deflate, br, zstd' \ + --header 'Accept-Language: en-US,en;q=0.5' \ + --header 'Connection: keep-alive' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --header 'DNT: 1' \ + --header 'Priority: u=1' \ + --header 'Sec-Fetch-Dest: document' \ + --header 'Sec-Fetch-Mode: navigate' \ + --header 'Sec-Fetch-User: ?1' \ + --header 'Sec-GPC: 1' \ + --header 'Upgrade-Insecure-Requests: 1' \ + --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0' \ + --data username=$USERNAME \ + --data password=$PASSWORD \ + --data samlLogin=false \ + --data rememberme=off \ + --data name=$USERNAME \ + --data password=$PASSWORD \ + --data authType=Internal \ + --data CSRFTokenNameValue=OWASP_CSRFTOKEN=$CSRFTOKEN \ + --data OWASP_CSRFTOKEN=$CSRFTOKEN \ + --data locale=en \ + --data hasSelectedLocale=false 2>/dev/null) + +# APPSESSIONID Gets updated here so we need to reassign APPSESSIONID +APPSESSIONID=$(echo -e "$output" | awk '/APPSESSIONID/ {print $7}') +JWT_TOKEN=$(echo -e "$output" | awk '/MNTLA_JWT_TOKEN/ {print $7}') +echo -e "JWT_TOKEN: $JWT_TOKEN" + diff --git a/ise/ISE-bash-scripts/logout.bash b/ise/ISE-bash-scripts/logout.bash new file mode 100755 index 0000000..81440dc --- /dev/null +++ b/ise/ISE-bash-scripts/logout.bash @@ -0,0 +1,17 @@ +#!/bin/bash + +# Logging out +echo -e "Logging out" +curl -k "https://$HOSTNAME/admin/logout.jsp" \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/png,image/svg+xml,*/*;q=0.8' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate, br, zstd' \ + -H 'Connection: keep-alive' \ + -H "Cookie: APPSESSIONID=$APPSESSIONID; MNTLA_JWT_TOKEN=$JWT_TOKEN" \ + -H 'Upgrade-Insecure-Requests: 1' \ + -H 'Sec-Fetch-Dest: document' \ + -H 'Sec-Fetch-Mode: navigate' \ + -H 'Sec-Fetch-Site: same-origin' \ + -H 'Sec-Fetch-User: ?1' \ + -H 'Priority: u=0, i' diff --git a/ise/ise_logparser/.gitignore b/ise/ise_logparser/.gitignore new file mode 100644 index 0000000..1a4595e --- /dev/null +++ b/ise/ise_logparser/.gitignore @@ -0,0 +1,2 @@ +/target +*.log diff --git a/ise/ise_logparser/.python-version b/ise/ise_logparser/.python-version new file mode 100644 index 0000000..871f80a --- /dev/null +++ b/ise/ise_logparser/.python-version @@ -0,0 +1 @@ +3.12.3 diff --git a/ise/ise_logparser/README.md b/ise/ise_logparser/README.md new file mode 100644 index 0000000..fc426ae --- /dev/null +++ b/ise/ise_logparser/README.md @@ -0,0 +1,3 @@ +# ise-logparser + +Describe your project here. diff --git a/ise/ise_logparser/notes.md b/ise/ise_logparser/notes.md new file mode 100644 index 0000000..a98c9d5 --- /dev/null +++ b/ise/ise_logparser/notes.md @@ -0,0 +1,13 @@ +``` +pre_test_output := .* +start_marker := 'JOB START' +test_output := .* +end_marker := 'JOB END' +post_test_output := .* +report_marker := 'Report' +report := .* +summary_marker := 'Result Summary' +summary := .* +details_marker := 'Result Details' +details := .* +``` diff --git a/ise/ise_logparser/pyproject.toml b/ise/ise_logparser/pyproject.toml new file mode 100644 index 0000000..76f9e2b --- /dev/null +++ b/ise/ise_logparser/pyproject.toml @@ -0,0 +1,28 @@ +[project] +name = "ise-logparser" +version = "0.1.0" +description = "Add your description here" +authors = [ + { name = "Mira Kristipati", email = "akristip@cisco.com" } +] +dependencies = [ + "parsy>=2.1", + "icecream>=2.1.3", + "python-dotenv>=1.0.1", +] +readme = "README.md" +requires-python = ">= 3.8" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.rye] +managed = true +dev-dependencies = [] + +[tool.hatch.metadata] +allow-direct-references = true + +[tool.hatch.build.targets.wheel] +packages = ["src/ise_logparser"] diff --git a/ise/ise_logparser/requirements-dev.lock b/ise/ise_logparser/requirements-dev.lock new file mode 100644 index 0000000..91c16ad --- /dev/null +++ b/ise/ise_logparser/requirements-dev.lock @@ -0,0 +1,28 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +asttokens==2.4.1 + # via icecream +colorama==0.4.6 + # via icecream +executing==2.0.1 + # via icecream +icecream==2.1.3 + # via ise-logparser +parsy==2.1 + # via ise-logparser +pygments==2.18.0 + # via icecream +python-dotenv==1.0.1 + # via ise-logparser +six==1.16.0 + # via asttokens diff --git a/ise/ise_logparser/requirements.lock b/ise/ise_logparser/requirements.lock new file mode 100644 index 0000000..91c16ad --- /dev/null +++ b/ise/ise_logparser/requirements.lock @@ -0,0 +1,28 @@ +# generated by rye +# use `rye lock` or `rye sync` to update this lockfile +# +# last locked with the following flags: +# pre: false +# features: [] +# all-features: false +# with-sources: false +# generate-hashes: false +# universal: false + +-e file:. +asttokens==2.4.1 + # via icecream +colorama==0.4.6 + # via icecream +executing==2.0.1 + # via icecream +icecream==2.1.3 + # via ise-logparser +parsy==2.1 + # via ise-logparser +pygments==2.18.0 + # via icecream +python-dotenv==1.0.1 + # via ise-logparser +six==1.16.0 + # via asttokens diff --git a/ise/ise_logparser/src/main.py b/ise/ise_logparser/src/main.py new file mode 100755 index 0000000..589e7e1 --- /dev/null +++ b/ise/ise_logparser/src/main.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +import re +from pathlib import Path +from dotenv import dotenv_values +import parsy as ps +from icecream import ic +import os +from pprint import pprint as print +from parsy import regex, seq + +# TODO: (akristip) refactor these to use `<<` instead of capture groups +parse_header = regex( + r"(.*)(^[^\n]*-+\n.*EASYPY JOB START.*?-+\|\n)", + re.MULTILINE | re.DOTALL, + 1, +) +parse_test_output = regex( + r"(.*)(^[^\n]*-+\n.*EASYPY JOB END.*?-+\|)", + re.MULTILINE | re.DOTALL, + 1, +) +parse_post_test = regex( + r"(.*)(\+-+\+\n\| +Easypy Report +\|\n\+-+\+)", + re.MULTILINE | re.DOTALL, + 1, +) +parse_report = regex( + r"(.*)(\+-+\+\n\| +Task Result Summary +\|\n\+-+\+)", + re.MULTILINE | re.DOTALL, + 1, +) +parse_summary = regex( + r"(.*)(\+-+\+\n\| +Task Result Details +\|\n\+-+\+)", + re.MULTILINE | re.DOTALL, + 1, +) + +timestamp = regex(r"\d{4}-\d{2}-\d{2}.\d{2}:\d{2}:\d{2}(,\d{3})?") +log_level = regex(r" (.+?) ", 0, 1) +source = regex(r"\[([A-Za-z_]+)\]", 0, 1) +messsage = ps.any_char.until(ps.peek(timestamp) | ps.eof) + + +parse_details = regex(r".*", re.MULTILINE | re.DOTALL) +parse_sections = seq( + header=parse_header, + test_output=parse_test_output, + post_test=parse_post_test, + report=parse_report, + summary=parse_summary, + details=parse_details, +) +parse_lines = seq( + ts=timestamp, + level=log_level, + src=source, + msg=messsage.map(lambda x: "".join(x).strip()), +).many() + + +class Config(dict[str, str]): + def __init__(self): + self.dict = dotenv_values(".env") + + def __getitem__(self, key: str, /) -> str: + try: + return self.dict.__getitem__(key) + except KeyError: + return os.environ[key] + + def __setitem__(self, _key: str, _value: str, /): + raise NotImplementedError("Config is read-only") + + def __delitem__(self, _: str, /): + raise NotImplementedError("Config is read-only") + + def __iter__(self): + return iter(self.dict) + + def __len__(self): + return len(self.dict) + + def __repr__(self): + return self.dict.__repr__() + + +if __name__ == "__main__": + config = Config() + with Path(config["LOGFILE"]).open() as f: + log = f.read() + sections = parse_sections.parse(log) + lines = parse_lines.parse(sections["test_output"]) + ic(lines) diff --git a/ise/reset-ise-passwd/.gitignore b/ise/reset-ise-passwd/.gitignore new file mode 100644 index 0000000..9773ff1 --- /dev/null +++ b/ise/reset-ise-passwd/.gitignore @@ -0,0 +1,2 @@ +.venv +.ruff_cache diff --git a/reset-ise-passwd/default.nix b/ise/reset-ise-passwd/default.nix similarity index 90% rename from reset-ise-passwd/default.nix rename to ise/reset-ise-passwd/default.nix index ca9ee87..8d3bc2f 100644 --- a/reset-ise-passwd/default.nix +++ b/ise/reset-ise-passwd/default.nix @@ -6,7 +6,7 @@ pkgs.mkShell { python-pkgs.pexpect python-pkgs.icecream python-pkgs.mypy - python-pkgs.ruff + # python-pkgs.ruff ])) pkgs.openssh ]; diff --git a/reset-ise-passwd/main.py b/ise/reset-ise-passwd/main.py similarity index 100% rename from reset-ise-passwd/main.py rename to ise/reset-ise-passwd/main.py