From 31f41d76eb23a7701f2d9d98ac9ebdeb81989dbe Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Mon, 25 Sep 2023 09:57:00 -0400 Subject: [PATCH 01/72] Update to use poetry backend. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 20 ++++++----- build_extension.py | 34 +++++++++++++++++++ pyproject.toml | 48 +++++++++++++-------------- requirements-development.txt | 7 ---- requirements.txt | 1 - setup.py | 34 ------------------- 6 files changed, 69 insertions(+), 75 deletions(-) create mode 100644 build_extension.py delete mode 100644 requirements-development.txt delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index b2cd022f..1bcffd33 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -2,23 +2,27 @@ name: pyRACF Linting & Unit Test on: [push, pull_request] jobs: build: + strategy: + fail-fast: true + matrix: + python-versions: ["3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Python Setup uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | - python3 -m pip install --upgrade pip - python3 -m pip install -r requirements.txt - python3 -m pip install -r requirements-development.txt + curl -sSL https://install.python-poetry.org | python3 - + poetry env use ${{ matrix.python-version }} + poetry install --no-root - name: Flake8 - run: flake8 . + run: poetry flake8 . - name: Pylint - run: pylint --recursive=y . + run: poetry pylint --recursive=y . - name: Unit Test - run: coverage run tests/test_runner.py + run: poetry coverage run tests/test_runner.py - name: Code Coverage - run: coverage report -m + run: poetry coverage report -m diff --git a/build_extension.py b/build_extension.py new file mode 100644 index 00000000..707ed038 --- /dev/null +++ b/build_extension.py @@ -0,0 +1,34 @@ +"""Build IRRSMO00 Python extesion.""" + +import os + +from setuptools import Extension +from setuptools.command import build_ext + + +def build(setup_kwargs: dict): + """Python extension build entrypoint.""" + os.environ["_CC_CCMODE"] = "1" + os.environ["_CXX_CCMODE"] = "1" + os.environ["_C89_CCMODE"] = "1" + os.environ["_CC_EXTRA_ARGS"] = "1" + os.environ["_CXX_EXTRA_ARGS"] = "1" + os.environ["_C89_EXTRA_ARGS"] = "1" + os.environ["CC"] = "xlc" + os.environ["CXX"] = "xlc++" + setup_kwargs.update( + { + "ext_modules": [ + Extension( + "cpyracf", + sources=["pyracf/common/irrsmo00.c"], + extra_compile_args=[ + "-D_XOPEN_SOURCE_EXTENDED", + "-Wc,lp64,langlvl(EXTC99),STACKPROTECT(ALL),", + "-qcpluscmt", + ], + ) + ], + "cmdclass": {"built_ext": build_ext}, + } + ) diff --git a/pyproject.toml b/pyproject.toml index 2e1e4d8b..228ec24e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,18 @@ [build-system] - build-backend = "setuptools.build_meta" - requires = ["setuptools>=61"] + build-backend = "poetry.masonry.api" + requires = ["poetry-core>=1.7.0", "setuptools>=61"] -[project] +[tool.poetry] name="pyracf" - version="1.0a2" + version="1.0a3" description="Python interface to RACF using IRRSMO00 RACF Callable Service." authors = [ - {name = "Joe Bostian", email = "jbostian@ibm.com"}, - {name = "Frank De Gilio", email = "degilio@us.ibm.com"}, - {name = "Leonard J. Carcaramo Jr", email = "lcarcaramo@ibm.com"}, - {name = "Elijah Swift", email = "elijah.swift@ibm.com"}, + "Joe Bostian ", + "Frank De Gilio ", + "Leonard J. Carcaramo Jr ", + "Elijah Swift ", ] readme = "README.md" - requires-python = ">=3.10" classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -28,24 +27,23 @@ "Topic :: System :: Hardware :: Mainframes", "Topic :: System :: Systems Administration", ] - dynamic = ["dependencies"] -[tool.setuptools.dynamic] - dependencies = { file = "requirements.txt" } +[tool.poetry.build] + script = "build_extension.py" + generate-setup-file = true -[tool.setuptools] - packages=[ - "pyracf", - "pyracf.access", - "pyracf.common", - "pyracf.connection", - "pyracf.data_set", - "pyracf.group", - "pyracf.resource", - "pyracf.setropts", - "pyracf.user", - ] - license-files=["LICENSE"] +[tool.poetry.dependencies] + python = ">=3.10" + defusedxml = ">=0.7.1" + +[tool.poetry.group.dev.dependencies] + isort = ">=5.12.0" + pre-commit = ">=3.4.0" + black = ">=23.7.0" + flake8 = ">=6.1.0" + pylint = ">=2.17.5" + coverage = ">=7.3.1" + wheel = ">=0.41.2" [tool.isort] profile = "black" diff --git a/requirements-development.txt b/requirements-development.txt deleted file mode 100644 index 3d8adcdb..00000000 --- a/requirements-development.txt +++ /dev/null @@ -1,7 +0,0 @@ -isort>=5.12.0 -pre-commit>=3.4.0 -black>=23.7.0 -flake8>=6.1.0 -pylint>=2.17.5 -coverage>=7.3.1 -wheel>=0.41.2 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c19d53ed..00000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -defusedxml>=0.7.1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 55576496..00000000 --- a/setup.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Build python extension for pyRACF.""" -import os - -from setuptools import Extension, setup - - -def main(): - """Entrypoint for pyRACF python extension build process.""" - setup_args = { - "ext_modules": [ - Extension( - "cpyracf", - sources=["pyracf/common/irrsmo00.c"], - extra_compile_args=[ - "-D_XOPEN_SOURCE_EXTENDED", - "-Wc,lp64,langlvl(EXTC99),STACKPROTECT(ALL),", - "-qcpluscmt", - ], - ) - ] - } - os.environ["_CC_CCMODE"] = "1" - os.environ["_CXX_CCMODE"] = "1" - os.environ["_C89_CCMODE"] = "1" - os.environ["_CC_EXTRA_ARGS"] = "1" - os.environ["_CXX_EXTRA_ARGS"] = "1" - os.environ["_C89_EXTRA_ARGS"] = "1" - os.environ["CC"] = "xlc" - os.environ["CXX"] = "xlc++" - setup(**setup_args) - - -if __name__ == "__main__": - main() From d07c3259f113304f785a4540343ad353e3cd79c0 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 07:59:01 -0400 Subject: [PATCH 02/72] Debug GitHub Actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index 1bcffd33..5e43f779 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -15,7 +15,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | - curl -sSL https://install.python-poetry.org | python3 - + curl -sSL https://install.python-poetry.org | python3 poetry env use ${{ matrix.python-version }} poetry install --no-root - name: Flake8 From 7018f677b3ee3d53b667702293b45627fe748bbf Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 08:05:45 -0400 Subject: [PATCH 03/72] Debug GitHub Actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index 5e43f779..854ef413 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -15,7 +15,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | - curl -sSL https://install.python-poetry.org | python3 + python3 -m pip install poetry poetry env use ${{ matrix.python-version }} poetry install --no-root - name: Flake8 From dbf85fc2ea58dfc36d194f3916a36f6935af65a6 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 08:11:46 -0400 Subject: [PATCH 04/72] Debug GitHub Actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index 854ef413..9e646b79 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: build: strategy: - fail-fast: true + fail-fast: false matrix: python-versions: ["3.10", "3.11"] runs-on: ubuntu-latest @@ -15,8 +15,8 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | - python3 -m pip install poetry - poetry env use ${{ matrix.python-version }} + curl -sSL https://install.python-poetry.org | python3 - + poetry env info poetry install --no-root - name: Flake8 run: poetry flake8 . From f30c67c9dbb4d62cf8927e4b3639f77632d7bb3b Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 08:20:33 -0400 Subject: [PATCH 05/72] Debug GitHub Actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index 9e646b79..d354e61d 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -17,6 +17,7 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python3 - poetry env info + poetry config virtualenvs.in-project true poetry install --no-root - name: Flake8 run: poetry flake8 . From 93a09fa29220ee6d3d7502a34f640726a3af81dc Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 08:23:03 -0400 Subject: [PATCH 06/72] Debug GitHub Actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index d354e61d..e5720d4d 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -17,13 +17,12 @@ jobs: run: | curl -sSL https://install.python-poetry.org | python3 - poetry env info - poetry config virtualenvs.in-project true poetry install --no-root - name: Flake8 - run: poetry flake8 . + run: poetry run flake8 . - name: Pylint - run: poetry pylint --recursive=y . + run: poetry run pylint --recursive=y . - name: Unit Test - run: poetry coverage run tests/test_runner.py + run: poetry run coverage run tests/test_runner.py - name: Code Coverage - run: poetry coverage report -m + run: poetry run coverage report -m From 35ad851e5f0af2cb26a34bacb62c0f3bdf60f3ad Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 09:52:31 -0400 Subject: [PATCH 07/72] Update Jenkinsfile to use Poetry. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 11 ++-- Jenkinsfile | 85 +++++++++++++++++++-------- 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index e5720d4d..b20a2b0d 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -13,11 +13,12 @@ jobs: uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install Dependencies - run: | - curl -sSL https://install.python-poetry.org | python3 - - poetry env info - poetry install --no-root + - name: Install Poetry + run: curl -sSL https://install.python-poetry.org | python3 - + - name: Show Poetry Environment Info + run: poetry env info + - name: Install Development Dependencies + run: poetry install --no-root - name: Flake8 run: poetry run flake8 . - name: Pylint diff --git a/Jenkinsfile b/Jenkinsfile index 3fe01bf7..9b98dec7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -70,11 +70,17 @@ pipeline { } } } + stage('Install Poetry') { + steps { + clean_python_environment() + install_poetry(python_executables_and_wheels_map.keySet()[-1]) + } + } stage('Build Virtual Environments') { steps { script { for (python in python_executables_and_wheels_map.keySet()) { - build_virtual_environment(python) + build_poetry_environment(python) } } } @@ -119,6 +125,7 @@ pipeline { always { echo "Cleaning up workspace..." cleanWs() + clean_python_environment() } } } @@ -155,16 +162,25 @@ def create_python_executables_and_wheels_map(python_versions) { return python_executables_and_wheels_map } -def build_virtual_environment(python) { - echo "Building virtual environment for '${python}'..." +def clean_python_environment() { + echo "Cleaning Python environment..." + + sh "rm -rf ~/.cache && rm -rf ~/.local" +} + +def install_poetry(python) { + echo "Installing Poetry..." + + sh "curl -sSL https://install.python-poetry.org | ${python} -" +} + +def build_poetry_environment(python) { + echo "Building Poetry environment for '${python}'..." sh """ - ${python} --version - rm -rf venv_${python} - ${python} -m venv venv_${python} - . venv_${python}/bin/activate - ${python} -m pip install -r requirements.txt - ${python} -m pip install -r requirements-development.txt + poetry env use ${python} + poetry install --no-root + poetry env show """ } @@ -172,12 +188,11 @@ def lint_and_unit_test(python) { echo "Running linters and unit tests for '${python}'..." sh """ - . venv_${python}/bin/activate - ${python} -m flake8 . - ${python} -m pylint --recursive=y . - cd tests - ${python} -m coverage run test_runner.py - ${python} -m coverage report -m + poetry env use ${python} && poetry env show + poetry run flake8 . + poetry run pylint --recursive=y . + poetry run coverage run tests/test_runner.py + poetry run coverage report -m """ } @@ -185,10 +200,10 @@ def function_test(python, wheel) { echo "Running function test for '${python}'..." sh """ - git clean -f -d -e 'venv_*' - . venv_${python}/bin/activate - ${python} -m pip wheel . - ${python} -m pip install ${wheel} + git clean -f -d + poetry env use ${python} && poetry env show + poetry build + ${python} -m pip install dist/${wheel} cd tests/function_test ${python} function_test.py """ @@ -212,6 +227,18 @@ def publish( string( credentialsId: 'pyracf-github-access-token', variable: 'github_access_token' + ), + string( + credentialsId: 'pyracf-pypi-repository', + variable: 'pypi_repository' + ) + string( + credentialsId: 'pyracf-pypi-username', + variable: 'pypi_username' + ), + string( + credentialsId: 'pyracf-pypi-password', + variable: 'pypi_password' ) ] ) { @@ -250,6 +277,8 @@ def publish( ) ).trim() + sh 'poetry config repository.test ${pypi_repository}' + for (python in python_executables_and_wheels_map.keySet()) { def wheel_default = python_executables_and_wheels_map[python]["defaultName"] def wheel_publish = python_executables_and_wheels_map[python]["publishName"] @@ -257,9 +286,10 @@ def publish( echo "Cleaning repo and building '${wheel_default}'..." sh """ - git clean -f -d -e 'venv_*' - . venv_${python}/bin/activate - ${python} -m pip wheel . + git clean -f -d + poetry env use ${python} && poetry env info + poetry build + mv dist/${wheel_default} dist/${wheel_publish} """ echo "Uploading '${wheel_default}' as '${wheel_publish}' to '${release}' GitHub release..." @@ -272,7 +302,16 @@ def publish( + '-H "X-GitHub-Api-Version: 2022-11-28" ' + '-H "Content-Type: application/octet-stream" ' + "\"https://uploads.github.com/repos/ambitus/pyracf/releases/${release_id}/assets?name=${wheel_publish}\" " - + "--data-binary \"@${wheel_default}\"" + + "--data-binary \"@dist/${wheel_publish}\"" + ) + + echo "Uploading '${wheel_default}' as '${wheel_publish}' and pyracf-${reasese}.tar.gz to PyPi repository..." + + sh ( + 'poetry publish \\' + + '--repository=test \\' + + '--username=${pyracf_username} \\' + + '--password=${pyracf_password}' ) } } From d92aba15d6a41bd8c2690d28225edda264301d57 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 10:06:01 -0400 Subject: [PATCH 08/72] Debug Jenkinsfile. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9b98dec7..a1f20f84 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -231,7 +231,7 @@ def publish( string( credentialsId: 'pyracf-pypi-repository', variable: 'pypi_repository' - ) + ), string( credentialsId: 'pyracf-pypi-username', variable: 'pypi_username' From 98366c472cdd1955f9ca9fbd7082dbe9c6d859ea Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 11:49:08 -0400 Subject: [PATCH 09/72] Debug Jenkinsfile. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a1f20f84..436384ad 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -165,13 +165,16 @@ def create_python_executables_and_wheels_map(python_versions) { def clean_python_environment() { echo "Cleaning Python environment..." - sh "rm -rf ~/.cache && rm -rf ~/.local" + sh """ + rm -rf ~/.cache + rm -rf ~/.local + """ } def install_poetry(python) { echo "Installing Poetry..." - sh "curl -sSL https://install.python-poetry.org | ${python} -" + sh "bash -c 'curl -sSL https://install.python-poetry.org | ${python} -'" } def build_poetry_environment(python) { @@ -180,7 +183,7 @@ def build_poetry_environment(python) { sh """ poetry env use ${python} poetry install --no-root - poetry env show + poetry env info """ } @@ -188,7 +191,8 @@ def lint_and_unit_test(python) { echo "Running linters and unit tests for '${python}'..." sh """ - poetry env use ${python} && poetry env show + poetry env use ${python} + poetry env info poetry run flake8 . poetry run pylint --recursive=y . poetry run coverage run tests/test_runner.py @@ -201,7 +205,8 @@ def function_test(python, wheel) { sh """ git clean -f -d - poetry env use ${python} && poetry env show + poetry env use ${python} + poetry env info poetry build ${python} -m pip install dist/${wheel} cd tests/function_test From 7d83b45272c3ff1345bcba20292d16e3e1335031 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 12:21:26 -0400 Subject: [PATCH 10/72] Debug Publish Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 436384ad..9ca9958d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -282,7 +282,7 @@ def publish( ) ).trim() - sh 'poetry config repository.test ${pypi_repository}' + sh 'poetry config repositories.test ${pypi_repository}' for (python in python_executables_and_wheels_map.keySet()) { def wheel_default = python_executables_and_wheels_map[python]["defaultName"] @@ -299,18 +299,10 @@ def publish( echo "Uploading '${wheel_default}' as '${wheel_publish}' to '${release}' GitHub release..." - sh( - 'curl -f -v -L ' - + '-X POST ' - + '-H "Accept: application/vnd.github+json" ' - + '-H "Authorization: Bearer ${github_access_token}" ' - + '-H "X-GitHub-Api-Version: 2022-11-28" ' - + '-H "Content-Type: application/octet-stream" ' - + "\"https://uploads.github.com/repos/ambitus/pyracf/releases/${release_id}/assets?name=${wheel_publish}\" " - + "--data-binary \"@dist/${wheel_publish}\"" - ) + upload_asset(wheel_publish) + upload_asset("pyracf-${release}.tar.gz") - echo "Uploading '${wheel_default}' as '${wheel_publish}' and pyracf-${reasese}.tar.gz to PyPi repository..." + echo "Uploading '${wheel_default}' as '${wheel_publish}' and 'pyracf-${release}.tar.gz' to PyPi repository..." sh ( 'poetry publish \\' @@ -322,6 +314,19 @@ def publish( } } +def upload_asset(asset) { + sh( + 'curl -f -v -L ' + + '-X POST ' + + '-H "Accept: application/vnd.github+json" ' + + '-H "Authorization: Bearer ${github_access_token}" ' + + '-H "X-GitHub-Api-Version: 2022-11-28" ' + + '-H "Content-Type: application/octet-stream" ' + + "\"https://uploads.github.com/repos/ambitus/pyracf/releases/${release_id}/assets?name=${asset}\" " + + "--data-binary \"@dist/${asset}\"" + ) +} + def build_description(python_executables_and_wheels_map, release, milestone) { def description = "Release Milestone: ${milestone}\\n \\n \\n" From 2e52db9e3dca41700c3649f6799c82c0da469899 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 12:52:23 -0400 Subject: [PATCH 11/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 9ca9958d..6d8d0e7e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -100,7 +100,7 @@ pipeline { for (python in python_executables_and_wheels_map.keySet()) { function_test( python, - python_executables_and_wheels_map[python]["defaultName"] + python_executables_and_wheels_map[python]["wheelDefault"] ) } } @@ -152,10 +152,11 @@ def create_python_executables_and_wheels_map(python_versions) { for (version in python_versions) { python_executables_and_wheels_map["python3.${version}"] = [ - "defaultName": ( + "wheelDefault": ( "pyracf-${pyracf_version}-cp3${version}-cp3${version}-${os}_${zos_release}_${processor}.whl" ), - "publishName": "pyracf-${pyracf_version}-cp3${version}-none-any.whl" + "wheelPublish": "pyracf-${pyracf_version}-cp3${version}-none-any.whl", + "tarPublish": "pyracf-${pyracf_version}.tar.gz" ] } @@ -285,8 +286,9 @@ def publish( sh 'poetry config repositories.test ${pypi_repository}' for (python in python_executables_and_wheels_map.keySet()) { - def wheel_default = python_executables_and_wheels_map[python]["defaultName"] - def wheel_publish = python_executables_and_wheels_map[python]["publishName"] + def wheel_default = python_executables_and_wheels_map[python]["wheelDefault"] + def wheel_publish = python_executables_and_wheels_map[python]["wheelPublish"] + def tar_publish = python_executables_and_wheels_map[python]["tarPublish"] echo "Cleaning repo and building '${wheel_default}'..." @@ -299,8 +301,8 @@ def publish( echo "Uploading '${wheel_default}' as '${wheel_publish}' to '${release}' GitHub release..." - upload_asset(wheel_publish) - upload_asset("pyracf-${release}.tar.gz") + upload_asset(release_id, wheel_publish) + upload_asset(release_id, tar_publish) echo "Uploading '${wheel_default}' as '${wheel_publish}' and 'pyracf-${release}.tar.gz' to PyPi repository..." @@ -314,7 +316,7 @@ def publish( } } -def upload_asset(asset) { +def upload_asset(release_id, release_asset) { sh( 'curl -f -v -L ' + '-X POST ' @@ -322,8 +324,8 @@ def upload_asset(asset) { + '-H "Authorization: Bearer ${github_access_token}" ' + '-H "X-GitHub-Api-Version: 2022-11-28" ' + '-H "Content-Type: application/octet-stream" ' - + "\"https://uploads.github.com/repos/ambitus/pyracf/releases/${release_id}/assets?name=${asset}\" " - + "--data-binary \"@dist/${asset}\"" + + "\"https://uploads.github.com/repos/ambitus/pyracf/releases/${release_id}/assets?name=${release_asset}\" " + + "--data-binary \"@dist/${release_asset}\"" ) } @@ -331,13 +333,18 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def description = "Release Milestone: ${milestone}\\n \\n \\n" for (python in python_executables_and_wheels_map.keySet()) { - def wheel = python_executables_and_wheels_map[python]["publishName"] + def wheel = python_executables_and_wheels_map[python]["wheelPublish"] + def tar = python_executables_and_wheels_map[python]["tarPublish"] def python_executable = python def python_label = python.replace("python", "Python ") description += ( - "Install for ${python_label}:\\n" + "### Install for ${python_label}:\\n\\n" + + "* Wheel *(pre-built)*:\\n\\n " + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" + + "* Source Tar *(build on install)*:\\n\\n " + + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + + "&& ${python_executable} -m pip install ${tar}\\n```\\n\\n" ) } From 41a55b5f6d0f03e40be508aae27f5b9dbc4b3afc Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 13:01:02 -0400 Subject: [PATCH 12/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 6d8d0e7e..01fc77ed 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -309,8 +309,8 @@ def publish( sh ( 'poetry publish \\' + '--repository=test \\' - + '--username=${pyracf_username} \\' - + '--password=${pyracf_password}' + + '--username=${pypi_username} \\' + + '--password=${pypi_password}' ) } } @@ -339,12 +339,12 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def python_label = python.replace("python", "Python ") description += ( "### Install for ${python_label}:\\n\\n" - + "* Wheel *(pre-built)*:\\n\\n " - + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " - + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" + + "* Wheel *(pre-built)*:\\n\\n" + + "```\\n curl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + + "&& ${python_executable} -m pip install ${wheel}\\n ```\\n" + "* Source Tar *(build on install)*:\\n\\n " - + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " - + "&& ${python_executable} -m pip install ${tar}\\n```\\n\\n" + + "```\\n curl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + + "&& ${python_executable} -m pip install ${tar}\\n ```\\n\\n" ) } From 9c576b499263c8cc27b59cbfadd36bb45a4eb62e Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 13:37:24 -0400 Subject: [PATCH 13/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 01fc77ed..c17e48c4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -285,6 +285,8 @@ def publish( sh 'poetry config repositories.test ${pypi_repository}' + def tar_published = false + for (python in python_executables_and_wheels_map.keySet()) { def wheel_default = python_executables_and_wheels_map[python]["wheelDefault"] def wheel_publish = python_executables_and_wheels_map[python]["wheelPublish"] @@ -302,7 +304,10 @@ def publish( echo "Uploading '${wheel_default}' as '${wheel_publish}' to '${release}' GitHub release..." upload_asset(release_id, wheel_publish) - upload_asset(release_id, tar_publish) + if (tar_published == false) { + upload_asset(release_id, tar_publish) + tar_published = true + } echo "Uploading '${wheel_default}' as '${wheel_publish}' and 'pyracf-${release}.tar.gz' to PyPi repository..." @@ -339,7 +344,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def python_label = python.replace("python", "Python ") description += ( "### Install for ${python_label}:\\n\\n" - + "* Wheel *(pre-built)*:\\n\\n" + + "* Wheel *(pre-built)*:\\n\\n " + "```\\n curl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + "&& ${python_executable} -m pip install ${wheel}\\n ```\\n" + "* Source Tar *(build on install)*:\\n\\n " From a452db73cfa05736b10e8c1f42cf4bd962662fee Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 13:53:33 -0400 Subject: [PATCH 14/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index c17e48c4..a64850b0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -205,7 +205,7 @@ def function_test(python, wheel) { echo "Running function test for '${python}'..." sh """ - git clean -f -d + git clean -fdx poetry env use ${python} poetry env info poetry build @@ -295,7 +295,7 @@ def publish( echo "Cleaning repo and building '${wheel_default}'..." sh """ - git clean -f -d + git clean -fdx poetry env use ${python} && poetry env info poetry build mv dist/${wheel_default} dist/${wheel_publish} @@ -337,21 +337,23 @@ def upload_asset(release_id, release_asset) { def build_description(python_executables_and_wheels_map, release, milestone) { def description = "Release Milestone: ${milestone}\\n \\n \\n" + def tar = python_executables_and_wheels_map.keySet()[-1]["tarPublish"] for (python in python_executables_and_wheels_map.keySet()) { def wheel = python_executables_and_wheels_map[python]["wheelPublish"] - def tar = python_executables_and_wheels_map[python]["tarPublish"] def python_executable = python def python_label = python.replace("python", "Python ") description += ( - "### Install for ${python_label}:\\n\\n" - + "* Wheel *(pre-built)*:\\n\\n " - + "```\\n curl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " - + "&& ${python_executable} -m pip install ${wheel}\\n ```\\n" - + "* Source Tar *(build on install)*:\\n\\n " - + "```\\n curl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " - + "&& ${python_executable} -m pip install ${tar}\\n ```\\n\\n" + "### Install From ${python_label} Wheel Distribution *(pre-built)*:\\n" + + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" ) } + description += ( + "### Install From Source Distribution *(build on install)*:\\n" + + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + + "&& python3 -m pip install ${tar}\\n```\\n" + ) + return description } From b36be4ed755bdbb92b8c359753a63a8b9bb7c508 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:00:11 -0400 Subject: [PATCH 15/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index a64850b0..4185be28 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -336,10 +336,11 @@ def upload_asset(release_id, release_asset) { def build_description(python_executables_and_wheels_map, release, milestone) { def description = "Release Milestone: ${milestone}\\n \\n \\n" + def tar = "" - def tar = python_executables_and_wheels_map.keySet()[-1]["tarPublish"] for (python in python_executables_and_wheels_map.keySet()) { def wheel = python_executables_and_wheels_map[python]["wheelPublish"] + def tar = python_executables_and_wheels_map[python]["tarPublish"] def python_executable = python def python_label = python.replace("python", "Python ") description += ( From 1016a0046a0accc5f8f2bdee48ae0b15539a12bb Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:02:18 -0400 Subject: [PATCH 16/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4185be28..23be4cda 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -340,7 +340,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { for (python in python_executables_and_wheels_map.keySet()) { def wheel = python_executables_and_wheels_map[python]["wheelPublish"] - def tar = python_executables_and_wheels_map[python]["tarPublish"] + tar = python_executables_and_wheels_map[python]["tarPublish"] def python_executable = python def python_label = python.replace("python", "Python ") description += ( From c926ff948218b8bc8a04dffb5d6245fd9ddfd094 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:10:10 -0400 Subject: [PATCH 17/72] Debug publish. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 23be4cda..88a8a2ce 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -336,22 +336,22 @@ def upload_asset(release_id, release_asset) { def build_description(python_executables_and_wheels_map, release, milestone) { def description = "Release Milestone: ${milestone}\\n \\n \\n" - def tar = "" for (python in python_executables_and_wheels_map.keySet()) { def wheel = python_executables_and_wheels_map[python]["wheelPublish"] - tar = python_executables_and_wheels_map[python]["tarPublish"] def python_executable = python def python_label = python.replace("python", "Python ") description += ( - "### Install From ${python_label} Wheel Distribution *(pre-built)*:\\n" + "Install From ${python_label} Wheel Distribution *(pre-built)*:\\n" + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" ) } + def python = python_executables_and_wheels_map[python].keySet[-1] + def tar = python_executables_and_wheels_map[python]["tarPublish"] description += ( - "### Install From Source Distribution *(build on install)*:\\n" + "Install From Source Distribution *(build on install)*:\\n" + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" ) From 70e2eb1b864347fea8de9611176e2604cd636ada Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:12:41 -0400 Subject: [PATCH 18/72] Cleanup Jenkinsfile. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 88a8a2ce..148c28c0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -308,6 +308,9 @@ def publish( upload_asset(release_id, tar_publish) tar_published = true } + else { + sh "rm dist/${tar_publish}" + } echo "Uploading '${wheel_default}' as '${wheel_publish}' and 'pyracf-${release}.tar.gz' to PyPi repository..." From 2eba7127173ade13e10f4d4d3119bec4c8082b90 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:17:31 -0400 Subject: [PATCH 19/72] Cleanup Jenkinsfile. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 148c28c0..7d06eb8b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -351,7 +351,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { ) } - def python = python_executables_and_wheels_map[python].keySet[-1] + def python = python_executables_and_wheels_map.keySet[-1] def tar = python_executables_and_wheels_map[python]["tarPublish"] description += ( "Install From Source Distribution *(build on install)*:\\n" From 97d9e79f47e5ae2600f6289963ee9af45ca3bd81 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Tue, 26 Sep 2023 14:22:37 -0400 Subject: [PATCH 20/72] Cleanup Jenkinsfile. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 7d06eb8b..ffb968bc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -351,7 +351,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { ) } - def python = python_executables_and_wheels_map.keySet[-1] + def python = python_executables_and_wheels_map.keySet()[-1] def tar = python_executables_and_wheels_map[python]["tarPublish"] description += ( "Install From Source Distribution *(build on install)*:\\n" From 3fa1ecb50f923d19b76cd291bd633dc30046f4fa Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 06:38:41 -0400 Subject: [PATCH 21/72] Update pre-commit hooks. Signed-off-by: Leonard Carcaramo --- .pre-commit-config.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a9d65a1b..4663da81 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,43 +3,43 @@ repos: hooks: - id: isort name: isort - entry: isort . + entry: poetry run isort . language: system pass_filenames: false always_run: true - id: black name: black - entry: black . + entry: poetry run black . language: system pass_filenames: false always_run: true - id: flake8 name: flake8 - entry: flake8 . + entry: poetry run flake8 . language: system pass_filenames: false always_run: true - id: pylint name: pylint - entry: pylint --recursive=y . + entry: poetry run pylint --recursive=y . language: system pass_filenames: false always_run: true - id: unittest name: unittest - entry: coverage run tests/test_runner.py + entry: poetry run coverage run tests/test_runner.py language: system pass_filenames: false always_run: true - id: coverage-html name: coverage-html - entry: coverage html + entry: poetry run coverage html language: system pass_filenames: false always_run: true - id: coverage name: coverage - entry: coverage report -m + entry: poetry run coverage report -m language: system pass_filenames: false always_run: true From e37dc4869c61f6b0bd5bcb414f2bf7eeb7ca8537 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 07:52:53 -0400 Subject: [PATCH 22/72] Update Contribution guidelines and pyproject.toml, and cleanup. Signed-off-by: Leonard Carcaramo --- .gitignore | 5 ++++- CONTRIBUTING.md | 47 ++++++++++++++++++++++++++++++++-------------- Jenkinsfile | 4 ++-- build_extension.py | 2 +- pyproject.toml | 8 +++++++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 936cca43..e39e59d9 100644 --- a/.gitignore +++ b/.gitignore @@ -170,4 +170,7 @@ _site .jekyll-cache .jekyll-metadata vendor -Gemfile.lock \ No newline at end of file +Gemfile.lock + +# Poetry +poetry.lock \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e003c908..77b7f85e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,17 +9,19 @@ The following are a set of guidelines to help you contribute. * [Ways to Contribute](#ways-to-contribute) -* [Coding](#coding) + * [Coding](#coding) -* [pre-commit Hooks](#pre-commit-hooks) + * [pre-commit Hooks](#pre-commit-hooks) -* [Adding New Functionality](#adding-new-functionality) + * [Adding New Functionality](#adding-new-functionality) -* [Testing](#testing) + * [Testing](#testing) -* [Fixing Bugs](#fixing-bugs) + * [Fixing Bugs](#fixing-bugs) -* [Adding or Fixing Documentation](#adding-or-fixing-documentation) + * [Adding or Fixing Documentation](#adding-or-fixing-documentation) + + * [Branch Naming Conventions](#branch-naming-conventions) * [Style Guidelines](#style-guidelines) @@ -52,14 +54,16 @@ If you want to write code, a good way to get started is by looking at the issues ### pre-commit Hooks To ensure that **code formatters _(isort and black)_**, **linters _(flake8 and pylint)_**, and **unit tests** are always run against your code on **every commit** set up the **pre-commit hooks**. -* Install development dependencies +> :warning: _pyRACF uses Poetry as it's **build backend** and for **dependency management**. After installing Poetry, ensure that the install location of Poetry is added to the `$PATH` **environment variable** if it is not already._ +* [Install Poetry](https://python-poetry.org/docs/#installation) + +* Install dependencies ```shell - python3 -m pip install -r requirements-development.txt + poetry install --no-root ``` * Setup pre-commit hooks -> :warning: _If your workstation cannot find `pre-commit`, ensure that the **Python package** `bin` directory location is added to the `$PATH` **environment variable**._ ```shell - pre-commit install -f + poetry run pre-commit install -f ``` ### Adding New Functionality @@ -70,6 +74,12 @@ If you have a new functionality that can be added to the package, open a GitHub The main way to test pyRACF is to write **unit tests** in the [`tests`](tests) folder which **mock** the real **IRRSMO00 API** to enable **XML generation** and **XML parsing** logic to be validated in a **fast** and **automated** way. The unit test suite can be run by just executing [`test_runner.py`](tests/test_runner.py). It is also recommended to do manual tests on a **z/OS system** for **new functionality** and **bug fixes** to test the real calls to **IRRSMO00**. +Since pyRACF uses Poetry as it's **build backend** and for **dependency management**, the pyRACF unit test suite should be executed as follows: + +```shell +poetry run coverage run tests/test_runner.py +``` + * **Unit Tests:** > :bulb: _See the Python [`unittest`](https://docs.python.org/3/library/unittest.html) and [`unittest.mock`](https://docs.python.org/3/library/unittest.mock.html) documentation for more details on writing test cases._ @@ -88,13 +98,22 @@ If you fix a bug, open a GitHub pull request against the `dev` branch with the f If any updates need to be made to the pyRACF documentation, open a GitHub pull request against the `gh-pages-dev` branch with your changes. This may include updates to document new functionality or updates to correct errors or mistakes in the existing documentation. +### Branch Naming Conventions + +Code branches should use the following naming conventions: + +* `wip/name` *(Work in progress branch that likely won't be finished soon)* +* `feat/name` *(Branch where new functionality or enhancements are being developed)* +* `bug/name` *(Branch where one or more bugs are being fixed)* +* `junk/name` *(Throwaway branch created for experimentation)* + ## Style Guidelines :bulb: _These steps can be done automatically using the [pre-commit Hooks](#pre-commit-hooks)._ * When adding code to pyRACF, follow the PEP8 style guide for Python -* The use of Flake8, Black, and pydocstyle as helpers is recommended -* It is strongly recommended that you perform a pylint check on your code. We expect it to have a pylint score greater than 9 +* The use of `pylint`, `flake8`, `black`, and `isort` is required. +* We expect all contributions to pass `flake8` and to have a `pylint` score of **10**. ## Contribution checklist @@ -106,8 +125,8 @@ When contributing to pyRACF, think about the following: * Add any available test cases to `/tests`. * Verify `__init__.py` files are updated properly. * Ensure that you have __pre-commit Hooks__ setup to ensure that **isort**, **black**, **flake8**, and **pylint** are run against the code for every commit you make. -* Run unit test suite by executing `python3 tests/test_runner.py`. -* Install pyRACF on a z/OS system and do a smoke test to make sure no regressions have been introduced with the C code that interfaces with IRRSOM00. +* Run unit test suite by executing `poetry run coverage run tests/test_runner.py`. +* Install pyRACF on a z/OS system and do a smoke test to make sure no regressions have been introduced with the C code that interfaces with IRRSOM00. [`function_test.py`](tests/function_test/function_test.py) can be used for this smoke test. ## Found a bug? diff --git a/Jenkinsfile b/Jenkinsfile index ffb968bc..f99c2fd9 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -345,7 +345,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def python_executable = python def python_label = python.replace("python", "Python ") description += ( - "Install From ${python_label} Wheel Distribution *(pre-built)*:\\n" + "Install From **${python_label} Wheel Distribution** *(pre-built)*:\\n" + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${wheel} " + "&& ${python_executable} -m pip install ${wheel}\\n```\\n" ) @@ -354,7 +354,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def python = python_executables_and_wheels_map.keySet()[-1] def tar = python_executables_and_wheels_map[python]["tarPublish"] description += ( - "Install From Source Distribution *(build on install)*:\\n" + "Install From **Source Distribution** *(build on install)*:\\n" + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" ) diff --git a/build_extension.py b/build_extension.py index 707ed038..95046322 100644 --- a/build_extension.py +++ b/build_extension.py @@ -1,4 +1,4 @@ -"""Build IRRSMO00 Python extesion.""" +"""Build IRRSMO00 (cpyracf) Python extesion.""" import os diff --git a/pyproject.toml b/pyproject.toml index 228ec24e..d36603e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,13 +6,20 @@ name="pyracf" version="1.0a3" description="Python interface to RACF using IRRSMO00 RACF Callable Service." + license = "Apache-2.0" authors = [ "Joe Bostian ", "Frank De Gilio ", "Leonard J. Carcaramo Jr ", "Elijah Swift ", ] + maintainers = [ + "Leonard J. Carcaramo Jr ", + "Elijah Swift ", + ] readme = "README.md" + repository = "https://github.com/ambitus/pyracf" + documentation = "https://ambitus.github.io/pyracf/" classifiers=[ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -52,7 +59,6 @@ max-args = 6 max-returns = 7 max-attributes = 10 - ignore-patterns = "venv_*" [tool.pylint.'MESSAGES CONTROL'] disable = """ From 62923b1f6ef36d16628cdfbb8ceaf1c8fb44be19 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 08:17:20 -0400 Subject: [PATCH 23/72] Debug source distribution. Signed-off-by: Leonard Carcaramo --- Jenkinsfile | 1 + README.md | 3 ++- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f99c2fd9..85387d5e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -355,6 +355,7 @@ def build_description(python_executables_and_wheels_map, release, milestone) { def tar = python_executables_and_wheels_map[python]["tarPublish"] description += ( "Install From **Source Distribution** *(build on install)*:\\n" + + "> :warning: _Requires z/OS XLC compiler._\\n" + "```\\ncurl -O -L https://github.com/ambitus/pyracf/releases/download/${release}/${tar} " + "&& python3 -m pip install ${tar}\\n```\\n" ) diff --git a/README.md b/README.md index 336c63cb..527ec852 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ As automation becomes more and more prevalent, the need to manage the security e ## Authors +* Joe Bostian: jbostian@ibm.com +* Frank De Gilio: degilio@us.ibm.com * Leonard Carcaramo: lcarcaramo@ibm.com * Elijah Swift: Elijah.Swift@ibm.com -* Joseph Bostian: jbostian@us.ibm.com diff --git a/pyproject.toml b/pyproject.toml index d36603e1..0dde3ad3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] - build-backend = "poetry.masonry.api" + build-backend = "poetry.core.masonry.api" requires = ["poetry-core>=1.7.0", "setuptools>=61"] [tool.poetry] From b39cfa1e7d032cf6c39a05c8f20ed85a6f83c37c Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 08:58:27 -0400 Subject: [PATCH 24/72] Introduce bug. Signed-off-by: Leonard Carcaramo --- pyracf/user/user_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 0984979c..df3eea35 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -338,7 +338,7 @@ def remove_class_authorizations( ) return self._to_steps(result) - def delete_all_class_authorizations(self, userid: str) -> Union[dict, bool, bytes]: + def delete_all_class_authorizations(self, userid: str) -> Union[dict, False, bytes]: """Delete all classes from a users class authorizations.""" current_class_authorizations = self.get_class_authorizations(userid) if not current_class_authorizations: From 03f0b2b8e9317b204600f5634a1786f4a0177d4d Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 09:14:43 -0400 Subject: [PATCH 25/72] Debug GitHub actions. Signed-off-by: Leonard Carcaramo --- .github/workflows/.github-actions.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index b20a2b0d..bb2e2be2 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -5,11 +5,11 @@ jobs: strategy: fail-fast: false matrix: - python-versions: ["3.10", "3.11"] + python-version: ["3.10", "3.11"] runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Python Setup + - name: Set Up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} From 87b0da4fda14819a75866b6e65e3013591c874d8 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Wed, 27 Sep 2023 09:23:02 -0400 Subject: [PATCH 26/72] Fix bug. Signed-off-by: Leonard Carcaramo --- pyracf/user/user_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index df3eea35..0984979c 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -338,7 +338,7 @@ def remove_class_authorizations( ) return self._to_steps(result) - def delete_all_class_authorizations(self, userid: str) -> Union[dict, False, bytes]: + def delete_all_class_authorizations(self, userid: str) -> Union[dict, bool, bytes]: """Delete all classes from a users class authorizations.""" current_class_authorizations = self.get_class_authorizations(userid) if not current_class_authorizations: From c729343c9b1f376b444362725b456c6afd258621 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 5 Oct 2023 15:38:40 -0400 Subject: [PATCH 27/72] Update dependencies. Signed-off-by: Leonard Carcaramo --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0dde3ad3..5822a2d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,10 +46,10 @@ [tool.poetry.group.dev.dependencies] isort = ">=5.12.0" pre-commit = ">=3.4.0" - black = ">=23.7.0" + black = ">=23.9.1" flake8 = ">=6.1.0" - pylint = ">=2.17.5" - coverage = ">=7.3.1" + pylint = ">=3.0.0" + coverage = ">=7.3.2" wheel = ">=0.41.2" [tool.isort] From 7f8d26f59740dba9415fcf9555f33c2d14f3a4ea Mon Sep 17 00:00:00 2001 From: ElijahSwiftIBM Date: Wed, 11 Oct 2023 17:24:45 -0400 Subject: [PATCH 28/72] Fix Add/Alter Disparity -Used "Fail on first error flag" which should stop Add requests from inadvertently altering existing users -Added AlterOperationError and raise this when Alter cannot extract the target profile before performing its operation --- pyracf/access/access_admin.py | 3 ++- pyracf/common/alter_operation_error.py | 24 +++++++++++++++++++ pyracf/common/irrsmo00.py | 2 +- pyracf/connection/connection_admin.py | 3 ++- pyracf/data_set/data_set_admin.py | 6 +++++ pyracf/group/group_admin.py | 6 +++++ pyracf/resource/resource_admin.py | 6 +++++ pyracf/user/user_admin.py | 6 +++++ .../alter_connection_request.xml | 1 + tests/connection/test_connection_constants.py | 2 +- tests/data_set/test_data_set_result_parser.py | 14 ++++++----- tests/group/test_group_result_parser.py | 14 ++++++----- tests/resource/test_resource_result_parser.py | 14 ++++++----- tests/user/test_user_constants.py | 2 -- tests/user/test_user_result_parser.py | 12 ++++++---- 15 files changed, 87 insertions(+), 28 deletions(-) create mode 100644 pyracf/common/alter_operation_error.py diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 85d9e64d..a8f52925 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -2,9 +2,10 @@ from typing import List, Union -from pyracf.access.access_request import AccessRequest from pyracf.common.security_admin import SecurityAdmin +from .access_request import AccessRequest + class AccessAdmin(SecurityAdmin): """RACF Access Administration.""" diff --git a/pyracf/common/alter_operation_error.py b/pyracf/common/alter_operation_error.py new file mode 100644 index 00000000..6f046938 --- /dev/null +++ b/pyracf/common/alter_operation_error.py @@ -0,0 +1,24 @@ +"""Exception to use when Alter operation would add a new profile.""" + + +class AlterOperationError(Exception): + """ + Raised when a profile passed into an Alter is not successfully extracted. + """ + + def __init__(self, profile_name: str, class_name: str) -> None: + self.message = "Security request made to IRRSMO00 failed." + admin_types = ["USER", "GROUP", "DATASET"] + if class_name not in admin_types: + self.message += ( + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a profile in the {class_name} class." + ) + else: + self.message += ( + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a {class_name} profile." + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/common/irrsmo00.py b/pyracf/common/irrsmo00.py index fb7204c9..d8a503d6 100644 --- a/pyracf/common/irrsmo00.py +++ b/pyracf/common/irrsmo00.py @@ -21,7 +21,7 @@ def __init__(self) -> None: def call_racf(self, request_xml: bytes, precheck: bool = False) -> str: """Make request to call_irrsmo00 in the cpyracf Python extension.""" - options = 11 if precheck else 9 + options = 15 if precheck else 13 return call_irrsmo00( xml_str=request_xml, xml_len=len(request_xml), opts=options ).decode("cp1047") diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index d175dbda..e9c507c7 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -3,7 +3,8 @@ from typing import List, Union from pyracf.common.security_admin import SecurityAdmin -from pyracf.connection.connection_request import ConnectionRequest + +from .connection_request import ConnectionRequest class ConnectionAdmin(SecurityAdmin): diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index d711dca0..72d9943f 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -2,7 +2,9 @@ from typing import List, Union +from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin +from pyracf.common.security_request_error import SecurityRequestError from .data_set_request import DataSetRequest @@ -117,6 +119,10 @@ def alter( volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: + try: + self.extract(data_set) + except SecurityRequestError: + raise AlterOperationError(data_set, "DATASET") """Alter an existing data set profile.""" self._build_segment_dictionaries(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index 60253c98..1945acfb 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -2,7 +2,9 @@ from typing import List, Union +from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin +from pyracf.common.security_request_error import SecurityRequestError from .group_request import GroupRequest @@ -131,6 +133,10 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, group: str, traits: dict = {}) -> Union[dict, bytes]: """Alter an existing group.""" + try: + self.extract(group) + except SecurityRequestError: + raise AlterOperationError(group, "GROUP") self._build_segment_dictionaries(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index bae65a7b..cd60a27e 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -2,7 +2,9 @@ from typing import List, Union +from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin +from pyracf.common.security_request_error import SecurityRequestError from .resource_request import ResourceRequest @@ -228,6 +230,10 @@ def alter( self, resource: str, class_name: str, traits: dict = {} ) -> Union[dict, bytes]: """Alter an existing general resource profile.""" + try: + self.extract(resource, class_name) + except SecurityRequestError: + raise AlterOperationError(resource, class_name) self._build_segment_dictionaries(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 0984979c..2860a817 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -2,7 +2,9 @@ from typing import List, Union +from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin +from pyracf.common.security_request_error import SecurityRequestError from .user_request import UserRequest @@ -404,6 +406,10 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: """Alter an existing user.""" + try: + self.extract(userid) + except SecurityRequestError: + raise AlterOperationError(userid, "USER") self._build_segment_dictionaries(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) diff --git a/tests/connection/connection_request_samples/alter_connection_request.xml b/tests/connection/connection_request_samples/alter_connection_request.xml index b39b16c9..f6c274d1 100644 --- a/tests/connection/connection_request_samples/alter_connection_request.xml +++ b/tests/connection/connection_request_samples/alter_connection_request.xml @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/tests/connection/test_connection_constants.py b/tests/connection/test_connection_constants.py index b1cd686c..e47de804 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -62,7 +62,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Alter Connection TEST_ALTER_CONNECTION_REQUEST_XML = get_sample("alter_connection_request.xml") TEST_ALTER_CONNECTION_REQUEST_TRAITS = { - "base:operator": False, + "base:operations": False, "base:special": True, } diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 924e5fdf..672f476a 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -62,9 +62,10 @@ def test_data_set_admin_can_parse_alter_data_set_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, + ] self.assertEqual( self.data_set_admin.alter( "ESWIFT.TEST.T1136242.P3020470", @@ -78,9 +79,10 @@ def test_data_set_admin_can_parse_alter_data_set_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.data_set_admin.alter( "ESWIFT.TEST.T1136242.P3020470", diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 8a2f63cb..4f906c85 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -58,9 +58,10 @@ def test_group_admin_can_parse_alter_group_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, + ] self.assertEqual( self.group_admin.alter( "TESTGRP0", traits=TestGroupConstants.TEST_ALTER_GROUP_REQUEST_TRAITS @@ -73,9 +74,10 @@ def test_group_admin_can_parse_alter_group_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.group_admin.alter( "TESTGRP0", diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 0fa402a3..d60700d6 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -56,9 +56,10 @@ def test_resource_admin_can_parse_alter_resource_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML, + ] self.assertEqual( self.resource_admin.alter( "TESTING", @@ -73,9 +74,10 @@ def test_resource_admin_can_parse_alter_resource_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.resource_admin.alter( "TESTING", diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 4213b47c..99c53d1c 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -112,7 +112,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "base:name": "Squidward", "base:owner": "leonard", "base:special": True, - "base:operator": False, "omvs:uid": "2424", "omvs:home": "/u/squidwrd", "omvs:program": "/bin/sh", @@ -135,7 +134,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_USER_REQUEST_XML = get_sample("alter_user_request.xml") TEST_ALTER_USER_REQUEST_TRAITS = { "base:special": False, - "base:operator": True, "omvs:home": "/u/clarinet", "omvs:program": False, } diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index c3b0ef8e..59d9628f 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -61,9 +61,10 @@ def test_user_admin_can_parse_alter_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, + ] self.assertEqual( self.user_admin.alter( "squidwrd", traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS @@ -76,7 +77,10 @@ def test_user_admin_can_parse_alter_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.user_admin.alter( "squidwrd", traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS From a4ea8e69201153b570dc9e75d230a7784f95e907 Mon Sep 17 00:00:00 2001 From: ElijahSwiftIBM Date: Thu, 12 Oct 2023 10:17:03 -0400 Subject: [PATCH 29/72] Streamline Access and Connections Access and Connection Admin had no difference between Add and Alter commands. The operations "under the covers" were exactly the same. Now that other function groups have more differences, these are merged to alter. --- pyracf/access/access_admin.py | 22 +---------- pyracf/connection/connection_admin.py | 11 +----- ...ccess_error.log => alter_access_error.log} | 28 +++++++------- ...s_success.log => alter_access_success.log} | 20 ++++------ .../add_access_request.xml | 6 --- .../alter_access_request.xml | 4 +- .../add_access_result_error.json | 23 ----------- .../add_access_result_error.xml | 14 ------- .../add_access_result_success.json | 23 ----------- .../add_access_result_success.xml | 14 ------- tests/access/test_access_constants.py | 13 +------ tests/access/test_access_debug_logging.py | 22 +++++------ tests/access/test_access_request_builder.py | 6 --- tests/access/test_access_result_parser.py | 38 +------------------ ...n_error.log => alter_connection_error.log} | 30 +++++++++++---- ...ccess.log => alter_connection_success.log} | 30 +++++++++++---- .../add_connection_request.xml | 3 -- .../alter_connection_request.xml | 2 +- ...onnection_give_group_auditor_authority.xml | 2 +- ...ection_give_group_operations_authority.xml | 2 +- ...onnection_give_group_special_authority.xml | 2 +- .../connection_set_group_access_attribute.xml | 2 +- .../add_connection_result_error.json | 24 ------------ .../add_connection_result_error.xml | 15 -------- .../add_connection_result_success.json | 20 ---------- .../add_connection_result_success.xml | 13 ------- tests/connection/test_connection_constants.py | 17 +-------- .../test_connection_debug_logging.py | 26 ++++++++----- .../test_connection_request_builder.py | 6 --- .../test_connection_result_parser.py | 30 --------------- 30 files changed, 110 insertions(+), 358 deletions(-) rename tests/access/access_log_samples/{add_access_error.log => alter_access_error.log} (80%) rename tests/access/access_log_samples/{add_access_success.log => alter_access_success.log} (79%) delete mode 100644 tests/access/access_request_samples/add_access_request.xml delete mode 100644 tests/access/access_result_samples/add_access_result_error.json delete mode 100644 tests/access/access_result_samples/add_access_result_error.xml delete mode 100644 tests/access/access_result_samples/add_access_result_success.json delete mode 100644 tests/access/access_result_samples/add_access_result_success.xml rename tests/connection/connection_log_samples/{add_connection_error.log => alter_connection_error.log} (79%) rename tests/connection/connection_log_samples/{add_connection_success.log => alter_connection_success.log} (77%) delete mode 100644 tests/connection/connection_request_samples/add_connection_request.xml delete mode 100644 tests/connection/connection_result_samples/add_connection_result_error.json delete mode 100644 tests/connection/connection_result_samples/add_connection_result_error.xml delete mode 100644 tests/connection/connection_result_samples/add_connection_result_success.json delete mode 100644 tests/connection/connection_result_samples/add_connection_result_success.xml diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index a8f52925..c226af20 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -54,22 +54,6 @@ def __init__( # ============================================================================ # Base Functions # ============================================================================ - def add( - self, - resource: str, - class_name: str, - auth_id: str, - traits: dict, - volume: Union[str, None] = None, - generic: bool = False, - ) -> Union[dict, bytes]: - """Create a new permission.""" - traits["base:id"] = auth_id - self._build_segment_dictionaries(traits) - access_request = AccessRequest(resource, class_name, "set", volume, generic) - self._add_traits_directly_to_request_xml_with_no_segments(access_request) - return self._make_request(access_request) - def alter( self, resource: str, @@ -79,13 +63,11 @@ def alter( volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: - """Alter an existing permission.""" + """Change a permission (or add a new one)""" traits["base:id"] = auth_id self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) - self._add_traits_directly_to_request_xml_with_no_segments( - access_request, alter=True - ) + self._add_traits_directly_to_request_xml_with_no_segments(access_request) return self._make_request(access_request) def delete( diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index e9c507c7..fbfe902b 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -122,20 +122,11 @@ def remove_group_access_attribute( # ============================================================================ # Base Functions # ============================================================================ - def add(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: - """Create a new group connection.""" - self._build_segment_dictionaries(traits) - connection_request = ConnectionRequest(userid, group, "set") - self._add_traits_directly_to_request_xml_with_no_segments(connection_request) - return self._make_request(connection_request) - def alter(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: """Alter an existing group connection.""" self._build_segment_dictionaries(traits) connection_request = ConnectionRequest(userid, group, "set") - self._add_traits_directly_to_request_xml_with_no_segments( - connection_request, alter=True - ) + self._add_traits_directly_to_request_xml_with_no_segments(connection_request) return self._make_request(connection_request) def delete(self, userid: str, group: str) -> Union[dict, bytes]: diff --git a/tests/access/access_log_samples/add_access_error.log b/tests/access/access_log_samples/alter_access_error.log similarity index 80% rename from tests/access/access_log_samples/add_access_error.log rename to tests/access/access_log_samples/alter_access_error.log index bf555c0a..07d546f5 100644 --- a/tests/access/access_log_samples/add_access_error.log +++ b/tests/access/access_log_samples/alter_access_error.log @@ -1,17 +1,17 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.add() + AccessAdmin.alter() { "base": { "base:access": { - "value": "READ", + "value": "ALTER", "operation": null }, "base:id": { - "value": "ESWIFT", + "value": "MCGINLEY", "operation": null } } @@ -20,20 +20,20 @@ [pyRACF:Debug] Request XML - AccessAdmin.add() + AccessAdmin.alter() - READ - ESWIFT + ALTER + MCGINLEY [pyRACF:Debug] Result XML - AccessAdmin.add() + AccessAdmin.alter() @@ -42,9 +42,9 @@ 8 16 - 8 - PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT) - ICH06004I TESTING NOT DEFINED TO RACF + 4 + PERMIT TESTING CLASS(ELIJTEST) ACCESS (ALTER) ID (MCGINLEY) + ICH06007I MCGINLEY NOT DEFINED TO RACF 4 @@ -54,7 +54,7 @@ [pyRACF:Debug] Result Dictionary - AccessAdmin.add() + AccessAdmin.alter() { @@ -68,10 +68,10 @@ { "safReturnCode": 8, "returnCode": 16, - "reasonCode": 8, - "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT)", + "reasonCode": 4, + "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (ALTER) ID (MCGINLEY)", "messages": [ - "ICH06004I TESTING NOT DEFINED TO RACF" + "ICH06007I MCGINLEY NOT DEFINED TO RACF" ] } ] diff --git a/tests/access/access_log_samples/add_access_success.log b/tests/access/access_log_samples/alter_access_success.log similarity index 79% rename from tests/access/access_log_samples/add_access_success.log rename to tests/access/access_log_samples/alter_access_success.log index 9b281917..36e5de83 100644 --- a/tests/access/access_log_samples/add_access_success.log +++ b/tests/access/access_log_samples/alter_access_success.log @@ -1,13 +1,13 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.add() + AccessAdmin.alter() { "base": { "base:access": { - "value": "READ", + "value": "NONE", "operation": null }, "base:id": { @@ -20,12 +20,12 @@ [pyRACF:Debug] Request XML - AccessAdmin.add() + AccessAdmin.alter() - READ + NONE ESWIFT @@ -33,7 +33,7 @@ [pyRACF:Debug] Result XML - AccessAdmin.add() + AccessAdmin.alter() @@ -43,8 +43,7 @@ 0 0 0 - PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT) - ICH06011I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED + PERMIT TESTING CLASS(ELIJTEST) ACCESS (NONE) ID (ESWIFT) 0 @@ -54,7 +53,7 @@ [pyRACF:Debug] Result Dictionary - AccessAdmin.add() + AccessAdmin.alter() { @@ -69,10 +68,7 @@ "safReturnCode": 0, "returnCode": 0, "reasonCode": 0, - "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT)", - "messages": [ - "ICH06011I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED" - ] + "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (NONE) ID (ESWIFT)" } ] }, diff --git a/tests/access/access_request_samples/add_access_request.xml b/tests/access/access_request_samples/add_access_request.xml deleted file mode 100644 index cfb45521..00000000 --- a/tests/access/access_request_samples/add_access_request.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - READ - ESWIFT - - \ No newline at end of file diff --git a/tests/access/access_request_samples/alter_access_request.xml b/tests/access/access_request_samples/alter_access_request.xml index 60ae67eb..8771e90f 100644 --- a/tests/access/access_request_samples/alter_access_request.xml +++ b/tests/access/access_request_samples/alter_access_request.xml @@ -1,6 +1,6 @@ - NONE - ESWIFT + NONE + ESWIFT \ No newline at end of file diff --git a/tests/access/access_result_samples/add_access_result_error.json b/tests/access/access_result_samples/add_access_result_error.json deleted file mode 100644 index f36df8e9..00000000 --- a/tests/access/access_result_samples/add_access_result_error.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "securityResult": { - "permission": { - "name": "TESTING", - "class": "ELIJTEST", - "operation": "set", - "requestId": "AccessRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT)", - "messages": [ - "ICH06004I TESTING NOT DEFINED TO RACF" - ] - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} \ No newline at end of file diff --git a/tests/access/access_result_samples/add_access_result_error.xml b/tests/access/access_result_samples/add_access_result_error.xml deleted file mode 100644 index fa6ba9d8..00000000 --- a/tests/access/access_result_samples/add_access_result_error.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - 8 - 16 - 8 - PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT) - ICH06004I TESTING NOT DEFINED TO RACF - - - 4 - 0 - \ No newline at end of file diff --git a/tests/access/access_result_samples/add_access_result_success.json b/tests/access/access_result_samples/add_access_result_success.json deleted file mode 100644 index dfc9dae6..00000000 --- a/tests/access/access_result_samples/add_access_result_success.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "securityResult": { - "permission": { - "name": "TESTING", - "class": "ELIJTEST", - "operation": "set", - "requestId": "AccessRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT)", - "messages": [ - "ICH06011I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED" - ] - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} \ No newline at end of file diff --git a/tests/access/access_result_samples/add_access_result_success.xml b/tests/access/access_result_samples/add_access_result_success.xml deleted file mode 100644 index fcf28168..00000000 --- a/tests/access/access_result_samples/add_access_result_success.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - 0 - 0 - 0 - PERMIT TESTING CLASS(ELIJTEST) ACCESS (READ) ID (ESWIFT) - ICH06011I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED - - - 0 - 0 - \ No newline at end of file diff --git a/tests/access/test_access_constants.py b/tests/access/test_access_constants.py index 4c07d80e..846e2a23 100644 --- a/tests/access/test_access_constants.py +++ b/tests/access/test_access_constants.py @@ -15,12 +15,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Access Administration Result Sample Data # ============================================================================ -# Add Access -TEST_ADD_ACCESS_RESULT_SUCCESS_XML = get_sample("add_access_result_success.xml") -TEST_ADD_ACCESS_RESULT_SUCCESS_DICTIONARY = get_sample("add_access_result_success.json") -TEST_ADD_ACCESS_RESULT_ERROR_XML = get_sample("add_access_result_error.xml") -TEST_ADD_ACCESS_RESULT_ERROR_DICTIONARY = get_sample("add_access_result_error.json") - # Alter Access TEST_ALTER_ACCESS_RESULT_SUCCESS_XML = get_sample("alter_access_result_success.xml") TEST_ALTER_ACCESS_RESULT_SUCCESS_DICTIONARY = get_sample( @@ -44,9 +38,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Access Administration Request Sample Data # ============================================================================ -# Add Access -TEST_ADD_ACCESS_REQUEST_XML = get_sample("add_access_request.xml") - # Alter Access TEST_ALTER_ACCESS_REQUEST_XML = get_sample("alter_access_request.xml") @@ -57,5 +48,5 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_ACCESS_SUCCESS_LOG = get_sample("add_access_success.log") -TEST_ADD_ACCESS_ERROR_LOG = get_sample("add_access_error.log") +TEST_ALTER_ACCESS_SUCCESS_LOG = get_sample("alter_access_success.log") +TEST_ALTER_ACCESS_ERROR_LOG = get_sample("alter_access_error.log") diff --git a/tests/access/test_access_debug_logging.py b/tests/access/test_access_debug_logging.py index 2a34cc13..8de63c71 100644 --- a/tests/access/test_access_debug_logging.py +++ b/tests/access/test_access_debug_logging.py @@ -24,37 +24,37 @@ class TestAccessDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Access + # Alter Access # ============================================================================ - def test_add_access_request_debug_log_works_on_success( + def test_alter_access_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ADD_ACCESS_RESULT_SUCCESS_XML + TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} + self.access_admin.alter( + "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ) success_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(success_log, TestAccessConstants.TEST_ADD_ACCESS_SUCCESS_LOG) + self.assertEqual(success_log, TestAccessConstants.TEST_ALTER_ACCESS_SUCCESS_LOG) - def test_add_access_request_debug_log_works_on_error( + def test_alter_access_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ADD_ACCESS_RESULT_ERROR_XML + TestAccessConstants.TEST_ALTER_ACCESS_RESULT_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} + self.access_admin.alter( + "TESTING", "ELIJTEST", "MCGINLEY", traits={"base:access": "ALTER"} ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestAccessConstants.TEST_ADD_ACCESS_ERROR_LOG) + self.assertEqual(error_log, TestAccessConstants.TEST_ALTER_ACCESS_ERROR_LOG) diff --git a/tests/access/test_access_request_builder.py b/tests/access/test_access_request_builder.py index d6473ee7..1e1dd71f 100644 --- a/tests/access/test_access_request_builder.py +++ b/tests/access/test_access_request_builder.py @@ -18,12 +18,6 @@ class TestAccessRequestBuilder(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) access_admin = AccessAdmin(generate_requests_only=True) - def test_access_admin_build_add_access_request(self): - result = self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} - ) - self.assertEqual(result, TestAccessConstants.TEST_ADD_ACCESS_REQUEST_XML) - def test_access_admin_build_alter_access_request(self): result = self.access_admin.alter( "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} diff --git a/tests/access/test_access_result_parser.py b/tests/access/test_access_result_parser.py index 2572ac0e..01c4ef27 100644 --- a/tests/access/test_access_result_parser.py +++ b/tests/access/test_access_result_parser.py @@ -19,40 +19,6 @@ class TestAccessResultParser(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) access_admin = AccessAdmin() - # ============================================================================ - # Add Access - # ============================================================================ - def test_access_admin_can_parse_add_access_success_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestAccessConstants.TEST_ADD_ACCESS_RESULT_SUCCESS_XML - ) - self.assertEqual( - self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} - ), - TestAccessConstants.TEST_ADD_ACCESS_RESULT_SUCCESS_DICTIONARY, - ) - - # Error in environment, TESTING resource already deleted/not added - def test_access_admin_can_parse_add_access_error_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestAccessConstants.TEST_ADD_ACCESS_RESULT_ERROR_XML - ) - with self.assertRaises(SecurityRequestError) as exception: - self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} - ) - self.assertEqual( - exception.exception.result, - TestAccessConstants.TEST_ADD_ACCESS_RESULT_ERROR_DICTIONARY, - ) - # ============================================================================ # Alter Access # ============================================================================ @@ -65,7 +31,7 @@ def test_access_admin_can_parse_alter_access_success_xml( ) self.assertEqual( self.access_admin.alter( - "TESTING", "ELITEST", "ESWIFT", traits={"base:access": "NONE"} + "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ), TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_DICTIONARY, ) @@ -80,7 +46,7 @@ def test_access_admin_can_parse_alter_access_error_xml( ) with self.assertRaises(SecurityRequestError) as exception: self.access_admin.alter( - "TESTING", "ELITEST", "MCGINLEY", traits={"base:access": "NONE"} + "TESTING", "ELIJTEST", "MCGINLEY", traits={"base:access": "ALTER"} ) self.assertEqual( exception.exception.result, diff --git a/tests/connection/connection_log_samples/add_connection_error.log b/tests/connection/connection_log_samples/alter_connection_error.log similarity index 79% rename from tests/connection/connection_log_samples/add_connection_error.log rename to tests/connection/connection_log_samples/alter_connection_error.log index c33b1402..00b44e8f 100644 --- a/tests/connection/connection_log_samples/add_connection_error.log +++ b/tests/connection/connection_log_samples/alter_connection_error.log @@ -1,25 +1,39 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.add() + ConnectionAdmin.alter() -{} +{ + "base": { + "base:operations": { + "value": false, + "operation": "delete" + }, + "base:special": { + "value": true, + "operation": null + } + } +} [pyRACF:Debug] Request XML - ConnectionAdmin.add() + ConnectionAdmin.alter() - + + + + [pyRACF:Debug] Result XML - ConnectionAdmin.add() + ConnectionAdmin.alter() @@ -29,7 +43,7 @@ 8 16 8 - CONNECT ESWIFT GROUP (TESTGRP0) + CONNECT ESWIFT GROUP (TESTGRP0) SPECIAL ICH51003I NAME NOT FOUND IN RACF DATA SET ICH02003I USER(S) NOT CONNECTED. @@ -41,7 +55,7 @@ [pyRACF:Debug] Result Dictionary - ConnectionAdmin.add() + ConnectionAdmin.alter() { @@ -56,7 +70,7 @@ "safReturnCode": 8, "returnCode": 16, "reasonCode": 8, - "image": "CONNECT ESWIFT GROUP (TESTGRP0)", + "image": "CONNECT ESWIFT GROUP (TESTGRP0) SPECIAL ", "messages": [ "ICH51003I NAME NOT FOUND IN RACF DATA SET", "ICH02003I USER(S) NOT CONNECTED." diff --git a/tests/connection/connection_log_samples/add_connection_success.log b/tests/connection/connection_log_samples/alter_connection_success.log similarity index 77% rename from tests/connection/connection_log_samples/add_connection_success.log rename to tests/connection/connection_log_samples/alter_connection_success.log index 5de10c4e..98c1a826 100644 --- a/tests/connection/connection_log_samples/add_connection_success.log +++ b/tests/connection/connection_log_samples/alter_connection_success.log @@ -1,25 +1,39 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.add() + ConnectionAdmin.alter() -{} +{ + "base": { + "base:operations": { + "value": false, + "operation": "delete" + }, + "base:special": { + "value": true, + "operation": null + } + } +} [pyRACF:Debug] Request XML - ConnectionAdmin.add() + ConnectionAdmin.alter() - + + + + [pyRACF:Debug] Result XML - ConnectionAdmin.add() + ConnectionAdmin.alter() @@ -29,7 +43,7 @@ 0 0 0 - CONNECT ESWIFT GROUP (TESTGRP0) + CONNECT ESWIFT GROUP (TESTGRP0) SPECIAL 0 @@ -39,7 +53,7 @@ [pyRACF:Debug] Result Dictionary - ConnectionAdmin.add() + ConnectionAdmin.alter() { @@ -54,7 +68,7 @@ "safReturnCode": 0, "returnCode": 0, "reasonCode": 0, - "image": "CONNECT ESWIFT GROUP (TESTGRP0)" + "image": "CONNECT ESWIFT GROUP (TESTGRP0) SPECIAL " } ] }, diff --git a/tests/connection/connection_request_samples/add_connection_request.xml b/tests/connection/connection_request_samples/add_connection_request.xml deleted file mode 100644 index 4860ba29..00000000 --- a/tests/connection/connection_request_samples/add_connection_request.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/tests/connection/connection_request_samples/alter_connection_request.xml b/tests/connection/connection_request_samples/alter_connection_request.xml index f6c274d1..7affef1e 100644 --- a/tests/connection/connection_request_samples/alter_connection_request.xml +++ b/tests/connection/connection_request_samples/alter_connection_request.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml b/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml index 8bb8b7af..fa848e9b 100644 --- a/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml b/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml index cfaf13fa..c11cc010 100644 --- a/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_special_authority.xml b/tests/connection/connection_request_samples/connection_give_group_special_authority.xml index b39b16c9..cffa6721 100644 --- a/tests/connection/connection_request_samples/connection_give_group_special_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_special_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_set_group_access_attribute.xml b/tests/connection/connection_request_samples/connection_set_group_access_attribute.xml index e5d15a33..92cf26c7 100644 --- a/tests/connection/connection_request_samples/connection_set_group_access_attribute.xml +++ b/tests/connection/connection_request_samples/connection_set_group_access_attribute.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_result_samples/add_connection_result_error.json b/tests/connection/connection_result_samples/add_connection_result_error.json deleted file mode 100644 index 2ef176de..00000000 --- a/tests/connection/connection_result_samples/add_connection_result_error.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "securityResult": { - "groupConnection": { - "name": "ESWIFT", - "group": "TESTGRP0", - "operation": "set", - "requestId": "ConnectionRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "CONNECT ESWIFT GROUP (TESTGRP0)", - "messages": [ - "ICH51003I NAME NOT FOUND IN RACF DATA SET", - "ICH02003I USER(S) NOT CONNECTED." - ] - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} \ No newline at end of file diff --git a/tests/connection/connection_result_samples/add_connection_result_error.xml b/tests/connection/connection_result_samples/add_connection_result_error.xml deleted file mode 100644 index 07f9fe66..00000000 --- a/tests/connection/connection_result_samples/add_connection_result_error.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - 8 - 16 - 8 - CONNECT ESWIFT GROUP (TESTGRP0) - ICH51003I NAME NOT FOUND IN RACF DATA SET - ICH02003I USER(S) NOT CONNECTED. - - - 4 - 0 - \ No newline at end of file diff --git a/tests/connection/connection_result_samples/add_connection_result_success.json b/tests/connection/connection_result_samples/add_connection_result_success.json deleted file mode 100644 index 0d4cc482..00000000 --- a/tests/connection/connection_result_samples/add_connection_result_success.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "securityResult": { - "groupConnection": { - "name": "ESWIFT", - "group": "TESTGRP0", - "operation": "set", - "requestId": "ConnectionRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "CONNECT ESWIFT GROUP (TESTGRP0)" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} \ No newline at end of file diff --git a/tests/connection/connection_result_samples/add_connection_result_success.xml b/tests/connection/connection_result_samples/add_connection_result_success.xml deleted file mode 100644 index 4a45e587..00000000 --- a/tests/connection/connection_result_samples/add_connection_result_success.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - 0 - 0 - 0 - CONNECT ESWIFT GROUP (TESTGRP0) - - - 0 - 0 - \ No newline at end of file diff --git a/tests/connection/test_connection_constants.py b/tests/connection/test_connection_constants.py index e47de804..1541cbe7 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -15,16 +15,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Connection Administration Result Sample Data # ============================================================================ -# Add Connection -TEST_ADD_CONNECTION_RESULT_SUCCESS_XML = get_sample("add_connection_result_success.xml") -TEST_ADD_CONNECTION_RESULT_SUCCESS_DICTIONARY = get_sample( - "add_connection_result_success.json" -) -TEST_ADD_CONNECTION_RESULT_ERROR_XML = get_sample("add_connection_result_error.xml") -TEST_ADD_CONNECTION_RESULT_ERROR_DICTIONARY = get_sample( - "add_connection_result_error.json" -) - # Alter Connection TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML = get_sample( "alter_connection_result_success.xml" @@ -56,9 +46,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Connection Administration Request Sample Data # ============================================================================ -# Add Connection -TEST_ADD_CONNECTION_REQUEST_XML = get_sample("add_connection_request.xml") - # Alter Connection TEST_ALTER_CONNECTION_REQUEST_XML = get_sample("alter_connection_request.xml") TEST_ALTER_CONNECTION_REQUEST_TRAITS = { @@ -102,5 +89,5 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_CONNECTION_SUCCESS_LOG = get_sample("add_connection_success.log") -TEST_ADD_CONNECTION_ERROR_LOG = get_sample("add_connection_error.log") +TEST_ALTER_CONNECTION_SUCCESS_LOG = get_sample("alter_connection_success.log") +TEST_ALTER_CONNECTION_ERROR_LOG = get_sample("alter_connection_error.log") diff --git a/tests/connection/test_connection_debug_logging.py b/tests/connection/test_connection_debug_logging.py index a2cdf963..5588d41d 100644 --- a/tests/connection/test_connection_debug_logging.py +++ b/tests/connection/test_connection_debug_logging.py @@ -24,37 +24,45 @@ class TestConnectionDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Connection + # Alter Connection # ============================================================================ - def test_add_connection_request_debug_log_works_on_success( + def test_alter_connection_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_SUCCESS_XML + TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.connection_admin.add("ESWIFT", "TESTGRP0") + self.connection_admin.alter( + "ESWIFT", + "TESTGRP0", + traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + ), success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestConnectionConstants.TEST_ADD_CONNECTION_SUCCESS_LOG + success_log, TestConnectionConstants.TEST_ALTER_CONNECTION_SUCCESS_LOG ) - def test_add_connection_request_debug_log_works_on_error( + def test_alter_connection_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_ERROR_XML + TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.connection_admin.add("ESWIFT", "TESTGRP0") + self.connection_admin.alter( + "ESWIFT", + "TESTGRP0", + traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + ), except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestConnectionConstants.TEST_ADD_CONNECTION_ERROR_LOG + error_log, TestConnectionConstants.TEST_ALTER_CONNECTION_ERROR_LOG ) diff --git a/tests/connection/test_connection_request_builder.py b/tests/connection/test_connection_request_builder.py index e1859bba..141670a5 100644 --- a/tests/connection/test_connection_request_builder.py +++ b/tests/connection/test_connection_request_builder.py @@ -18,12 +18,6 @@ class TestConnectionRequestBuilder(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) connection_admin = ConnectionAdmin(generate_requests_only=True) - def test_connection_admin_build_add_connection_request(self): - result = self.connection_admin.add("ESWIFT", "TESTGRP0") - self.assertEqual( - result, TestConnectionConstants.TEST_ADD_CONNECTION_REQUEST_XML - ) - def test_connection_admin_build_alter_connection_request(self): result = self.connection_admin.alter( "ESWIFT", diff --git a/tests/connection/test_connection_result_parser.py b/tests/connection/test_connection_result_parser.py index 1a1f7653..1e6e3893 100644 --- a/tests/connection/test_connection_result_parser.py +++ b/tests/connection/test_connection_result_parser.py @@ -19,36 +19,6 @@ class TestConnectionResultParser(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) connection_admin = ConnectionAdmin() - # ============================================================================ - # Add Connection - # ============================================================================ - def test_connection_admin_can_parse_add_connection_success_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_SUCCESS_XML - ) - self.assertEqual( - self.connection_admin.add("ESWIFT", "TESTGRP0"), - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_SUCCESS_DICTIONARY, - ) - - # Error in environment, TESTGRP0 group already deleted/not added - def test_connection_admin_can_parse_add_connection_error_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_ERROR_XML - ) - with self.assertRaises(SecurityRequestError) as exception: - self.connection_admin.add("ESWIFT", "TESTGRP0") - self.assertEqual( - exception.exception.result, - TestConnectionConstants.TEST_ADD_CONNECTION_RESULT_ERROR_DICTIONARY, - ) - # ============================================================================ # Alter Connection # ============================================================================ From abac43b6275e361a209da405fa3ce8cd3d13d7b5 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Sat, 21 Oct 2023 09:40:35 -0400 Subject: [PATCH 30/72] Fix setPassword bug, expand/rename all traits, and add extracted segment traits map for formatting. Signed-off-by: Leonard Carcaramo --- pyracf/access/access_admin.py | 30 +- pyracf/common/logger.py | 2 +- pyracf/common/security_admin.py | 58 +++- pyracf/connection/connection_admin.py | 14 +- pyracf/data_set/data_set_admin.py | 67 ++-- pyracf/group/group_admin.py | 25 +- pyracf/resource/resource_admin.py | 224 ++++++------- pyracf/setropts/setropts_admin.py | 200 ++++++------ pyracf/user/user_admin.py | 298 +++++++++--------- tests/common/test_logger.py | 32 ++ tests/test_runner.py | 2 + tests/user/test_user_constants.py | 20 +- tests/user/test_user_getters.py | 26 +- tests/user/test_user_setters.py | 14 +- ...add_user_additional_secret_added_error.log | 4 +- ...d_user_additional_secret_added_success.log | 4 +- .../user/user_log_samples/add_user_error.log | 4 +- ...add_user_passphrase_and_password_error.log | 4 +- ...d_user_passphrase_and_password_success.log | 4 +- .../add_user_passphrase_error.log | 4 +- .../add_user_passphrase_success.log | 4 +- .../add_user_password_error.log | 4 +- .../add_user_password_success.log | 4 +- .../user_log_samples/add_user_success.log | 4 +- .../extract_user_base_omvs_success.log | 16 +- ...> user_set_omvs_default_shell_request.xml} | 0 ... user_set_omvs_home_directory_request.xml} | 0 ..._user_result_base_omvs_csdata_success.json | 14 +- ...extract_user_result_base_omvs_success.json | 16 +- 29 files changed, 574 insertions(+), 524 deletions(-) create mode 100644 tests/common/test_logger.py rename tests/user/user_request_samples/{user_set_omvs_program_request.xml => user_set_omvs_default_shell_request.xml} (100%) rename tests/user/user_request_samples/{user_set_omvs_home_request.xml => user_set_omvs_home_directory_request.xml} (100%) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 85d9e64d..98ea7e59 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -21,24 +21,24 @@ def __init__( "base": { "base:access": "access", "base:delete": "racf:delete", - "base:fclass": "racf:fclass", - "base:fprofile": "racf:fprofile", - "base:fgeneric": "racf:fgeneric", - "base:fvolume": "racf:fvolume", + "base:model_profile_class": "racf:fclass", + "base:model_profile": "racf:fprofile", + "base:model_profile_generic": "racf:fgeneric", + "base:model_profile_volume": "racf:fvolume", "base:id": "authid", - "base:profile": "racf:profile", + "base:profile": "racf:profile", # Not documented? "base:reset": "racf:reset", "base:volume": "racf:volume", - "base:whenappc": "racf:whenappc", - "base:whencons": "racf:whencons", - "base:whenjes": "racf:whenjes", - "base:whenprog": "racf:whenprog", - "base:whenserv": "racf:whenserv", - "base:whensms": "racf:whensms", - "base:whensqlr": "racf:whensqlr", - "base:whensrv": "racf:whensrv", - "base:whensys": "racf:whensys", - "base:whenterm": "racf:whenterm", + "base:when_partner_lu_name": "racf:whenappc", + "base:when_console": "racf:whencons", + "base:when_jes": "racf:whenjes", + "base:when_program": "racf:whenprog", + "base:when_servauth": "racf:whenserv", + "base:when_sms": "racf:whensms", + "base:when_db2_role": "racf:whensqlr", + "base:when_service": "racf:whensrv", + "base:when_system": "racf:whensys", + "base:when_terminal": "racf:whenterm", } } super().__init__( diff --git a/pyracf/common/logger.py b/pyracf/common/logger.py index ed1f3dc8..07a491ae 100644 --- a/pyracf/common/logger.py +++ b/pyracf/common/logger.py @@ -166,7 +166,7 @@ def redact_result_xml( match = re.search(rf"{racf_key.upper()} +\(", xml_string) if not match: continue - xml_string = self.__redact_string(xml_string, match.end(), ") ") + xml_string = self.__redact_string(xml_string, match.end(), ")") return xml_string def __colorize_json(self, json_text: str) -> str: diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index c9540769..4b1282d0 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -16,6 +16,7 @@ class SecurityAdmin: """Base Class for RACF Administration Interface.""" _valid_segment_traits = {} + _extracted_key_value_pair_segment_traits_map = {} __logger = Logger() def __init__( @@ -393,11 +394,13 @@ def __format_data_set_generic_profile_data( for txt in list(filter(None, messages[i].split(" "))) ] ) - field = self._profile_field_to_camel_case(field) + field = self._profile_field_to_camel_case(current_segment, field) value = messages[i + 2] if "(" in value: value_tokens = value.split("(") - subfield = self._profile_field_to_camel_case(value_tokens[0].lower()) + subfield = self._profile_field_to_camel_case( + current_segment, value_tokens[0].lower() + ) profile[current_segment][field] = { subfield: self._clean_and_separate(value_tokens[-1].rstrip(")")) } @@ -432,7 +435,7 @@ def __format_user_profile_data( ): semi_tabular_data = messages[i : i + 3] self.__add_semi_tabular_data_to_segment( - profile[current_segment], semi_tabular_data + current_segment, profile[current_segment], semi_tabular_data ) i += 2 elif messages[i][:8] == " GROUP=": @@ -442,15 +445,19 @@ def __format_user_profile_data( profile[current_segment]["groups"][group] = {} message = messages[i] + messages[i + 1] + messages[i + 2] + messages[i + 3] self.__add_key_value_pairs_to_segment( - profile[current_segment]["groups"][group], message[17:] + current_segment, profile[current_segment]["groups"][group], message[17:] ) i += 3 elif "=" not in messages[i] and messages[i].strip()[:3] != "NO-": messages[i] = f"{messages[i]}={messages[i+1]}" - self.__add_key_value_pairs_to_segment(profile[current_segment], messages[i]) + self.__add_key_value_pairs_to_segment( + current_segment, profile[current_segment], messages[i] + ) i += 1 else: - self.__add_key_value_pairs_to_segment(profile[current_segment], messages[i]) + self.__add_key_value_pairs_to_segment( + current_segment, profile[current_segment], messages[i] + ) return i def __format_group_profile_data( @@ -467,10 +474,12 @@ def __format_group_profile_data( ): profile[current_segment]["users"] = [] elif "=" in messages[i]: - self.__add_key_value_pairs_to_segment(profile[current_segment], messages[i]) + self.__add_key_value_pairs_to_segment( + current_segment, profile[current_segment], messages[i] + ) elif "NO " in messages[i]: field_name = self._profile_field_to_camel_case( - messages[i].split("NO ")[1].strip().lower() + current_segment, messages[i].split("NO ")[1].strip().lower() ) if field_name in list_fields: profile[current_segment][field_name] = [] @@ -510,11 +519,15 @@ def __format_user_list_data( ] = self._cast_from_str(user_fields[3]) self.__add_key_value_pairs_to_segment( - profile[current_segment]["users"][user_index], messages[i + 1] + current_segment, + profile[current_segment]["users"][user_index], + messages[i + 1], ) self.__add_key_value_pairs_to_segment( - profile[current_segment]["users"][user_index], messages[i + 2] + current_segment, + profile[current_segment]["users"][user_index], + messages[i + 2], ) def __build_additional_segment_keys(self) -> Tuple[str, str]: @@ -530,7 +543,7 @@ def __build_additional_segment_keys(self) -> Tuple[str, str]: return (additional_segment_keys, no_segment_information_keys) def __add_semi_tabular_data_to_segment( - self, segment: dict, semi_tabular_data: List[str] + self, segment_name: str, segment: dict, semi_tabular_data: List[str] ) -> None: """Add semi-tabular data as key-value pairs to segment dictionary.""" heading_tokens = list(filter(("").__ne__, semi_tabular_data[0].split(" "))) @@ -539,7 +552,9 @@ def __add_semi_tabular_data_to_segment( values = semi_tabular_data[-1].split() keys_length = len(keys) for i in range(keys_length): - key = self._profile_field_to_camel_case(keys[i].strip().lower()) + key = self._profile_field_to_camel_case( + segment_name, keys[i].strip().lower() + ) segment[key] = self._cast_from_str(values[i]) def __format_semi_tabular_data( @@ -566,7 +581,7 @@ def __format_semi_tabular_data( ind_e1 = len(messages[i + 2]) field = self._profile_field_to_camel_case( - messages[i][indexes[j] : ind_e0].strip().lower() + current_segment, messages[i][indexes[j] : ind_e0].strip().lower() ) profile[current_segment][field] = self._clean_and_separate( messages[i + 2][indexes[j] : ind_e1] @@ -574,6 +589,7 @@ def __format_semi_tabular_data( def __add_key_value_pairs_to_segment( self, + segment_name: str, segment: dict, message: str, ) -> None: @@ -583,11 +599,14 @@ def __add_key_value_pairs_to_segment( key = tokens[0] for i in range(1, len(tokens)): sub_tokens = list(filter(("").__ne__, tokens[i].split(" "))) - value = sub_tokens[0].strip() + if not sub_tokens: + value = "NONE" + else: + value = sub_tokens[0].strip() if key[:3] == "NO-": key = key[3:] value = "N/A" - current_key = self._profile_field_to_camel_case(key.lower()) + current_key = self._profile_field_to_camel_case(segment_name, key.lower()) if current_key in list_fields: if current_key not in segment: segment[current_key] = [] @@ -612,7 +631,9 @@ def __add_key_value_pair_to_profile( self, message: str, profile: dict, current_segment: str ) -> None: """Generic function for extracting key-value pair from RACF profile data.""" - field = self._profile_field_to_camel_case(message.split("=")[0].strip().lower()) + field = self._profile_field_to_camel_case( + current_segment, message.split("=")[0].strip().lower() + ) profile[current_segment][field] = self._clean_and_separate( message.split("=")[1] ) @@ -712,8 +733,11 @@ def __cast_num(self, value: str) -> Union[int, float, str]: except ValueError: return value - def _profile_field_to_camel_case(self, field: str) -> str: + def _profile_field_to_camel_case(self, segment: str, field: str) -> str: """Convert a space delimited profile field to camel case.""" + if segment in self._extracted_key_value_pair_segment_traits_map: + if field in self._extracted_key_value_pair_segment_traits_map[segment]: + return self._extracted_key_value_pair_segment_traits_map[segment][field] field_tokens = field.replace("-", " ").replace(",", "").split() return field_tokens[0] + "".join( [field_token.title() for field_token in field_tokens[1:]] diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index d175dbda..27ddbb58 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -19,22 +19,18 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:adsp": "racf:adsp", + "base:automatic_data_set_protection": "racf:adsp", "base:auditor": "racf:auditor", - "base:auth": "racf:auth", - "base:cgauthda": "racf:cgauthda", - "base:cginitct": "racf:cginitct", - "base:cgljdate": "racf:cgljdate", - "base:cgljtime": "racf:cgljtime", + "base:group_authority": "racf:auth", "base:group": "racf:group", "base:group_access": "racf:grpacc", "base:operations": "racf:oper", "base:owner": "racf:owner", "base:resume": "racf:resume", "base:revoke": "racf:revoke", - "base:revokefl": "racf:revokefl", - "base:special": "racf:special", - "base:uacc": "racf:uacc", + "base:revokefl": "racf:revokefl", # What is the point of this. + "base:special": "racf:special", # Just need 'base:revoke', no? + "base:universal_access": "racf:uacc", } } super().__init__( diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index d711dca0..a95b065e 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -20,45 +20,42 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:altvol": "racf:altvol", - "base:category": "racf:category", - "base:creatdat": "racf:creatdat", - "base:data": "racf:data", - "base:dsns": "racf:dsns", - "base:dstype": "racf:dstype", - "base:erase": "racf:erase", - "base:fclass": "racf:fclass", - "base:fgeneric": "racf:fgeneric", - "base:fileseq": "racf:fileseq", - "base:from": "racf:from", - "base:groupnm": "racf:groupnm", - "base:history": "racf:history", - "base:id": "racf:id", - "base:lchgdat": "racf:lchgdat", + "base:alter_volume": "racf:altvol", + "base:audit_alter": "racf:audaltr", + "base:audit_control": "racf:audcntl", + "base:audit_none": "racf:audnone", + "base:audit_read": "racf:audread", + "base:audit_update": "racf:audupdt", + "base:security_categories": "racf:category", + "base:installation_data": "racf:data", + "base:erase_data_sets_on_delete": "racf:erase", + "base:model_profile_class": "racf:fclass", + "base:model_profile_generic": "racf:fgeneric", + "base:tape_data_set_file_sequence_number": "racf:fileseq", + "base:model_profile": "racf:from", + "base:model_profile_volume": "racf:fvolume", + "base:global_audit_alter": "racf:gaudaltr", + "base:global_audit_control": "racf:gaudcntl", + "base:global_audit_none": "racf:gaudnone", + "base:global_audit_read": "racf:gaudread", + "base:global_audit_update": "racf:gaudupdt", "base:level": "racf:level", - "base:lrefdat": "racf:lrefdat", - "base:model": "racf:model", - "base:noracf": "racf:noracf", - "base:notify": "racf:notify", + "base:data_set_model_profile": "racf:model", + "base:notify_userid": "racf:notify", "base:owner": "racf:owner", - "base:prefix": "racf:prefix", - "base:profile": "racf:profile", - "base:raudit": "racf:raudit", - "base:retpd": "racf:retpd", - "base:rgaudit": "racf:rgaudit", - "base:seclabel": "racf:seclabel", - "base:seclevel": "racf:seclevel", - "base:set": "racf:set", - "base:setonly": "racf:setonly", - "base:stats": "racf:stats", - "base:tape": "racf:tape", + "base:profile": "racf:profile", # Not documented? + "base:tape_data_set_security_retention_period": "racf:retpd", + "base:security_label": "racf:seclabel", + "base:security_level": "racf:seclevel", + "base:generic_not_allowed": "racf:set", + "base:generic_allowed": "racf:setonly", + "base:use_tape_data_set_profile": "racf:tape", "base:universal_access": "racf:uacc", - "base:unit": "racf:unit", - "base:volume": "racf:volume", - "base:volser": "racf:volser", - "base:warning": "racf:warning", + "base:data_set_allocation_unit": "racf:unit", + "base:volumes": "racf:volume", + "base:warn_on_insufficient_access": "racf:warning", }, - "dfp": {"dfp:resowner": "racf:resowner", "dfp:datakey": "racf:datakey"}, + "dfp": {"dfp:owner": "racf:resowner", "dfp:ckds_data_key": "racf:datakey"}, "tme": {"tme:roles": "racf:roles"}, } super().__init__( diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index 60253c98..f15f8bc4 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -20,26 +20,21 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:connects": "racf:connects", - "base:gauth": "racf:gauth", - "base:guserid": "racf:guserid", - "base:creatdat": "racf:creatdat", - "base:data": "racf:data", - "base:model": "racf:model", + "base:installation_data": "racf:data", + "base:data_set_model": "racf:model", "base:owner": "racf:owner", - "base:subgroup": "racf:subgroup", - "base:supgroup": "racf:supgroup", - "base:termuacc": "racf:termuacc", - "base:universl": "racf:universl", + "base:superior_group": "racf:supgroup", + "base:terminal_universal_access": "racf:termuacc", + "base:universal": "racf:universl", }, "dfp": { - "dfp:dataappl": "dataappl", - "dfp:dataclas": "dataclas", - "dfp:mgmtclas": "mgmtclas", - "dfp:storclas": "storclas", + "dfp:data_application": "dataappl", + "dfp:data_class": "dataclas", + "dfp:management_class": "mgmtclas", + "dfp:storage_class": "storclas", }, "omvs": { - "omvs:autogid": "racf:autogid", + "omvs:auto_gid": "racf:autogid", "omvs:gid": "gid", "omvs:shared": "racf:shared", }, diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index bae65a7b..8a975f7b 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -20,154 +20,156 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:appldata": "racf:appldata", - "base:automatc": "racf:automatc", - "base:category": "racf:category", - "base:creatdat": "racf:creatdat", - "base:data": "racf:data", - "base:fclass": "racf:fclass", - "base:fgeneric": "racf:fgeneric", - "base:fprofile": "racf:fprofile", - "base:history": "racf:history", - "base:lchgdat": "racf:lchgdat", + "base:application_data": "racf:appldata", + "base:audit_alter:": "racf:audaltr", + "base:audit_control": "racf:audcntl", + "base:audit_none": "racf:audnone", + "base:audit_read": "racf:audread", + "base:audit_update": "racf:audupdt", + "base:security_categories": "racf:category", + "base:installation_data": "racf:data", + "base:model_profile_class": "racf:fclass", + "base:model_profile_generic": "racf:fgeneric", + "base:model_profile": "racf:fprofile", + "base:model_profile_volume": "racf:fvolume", + "base:global_audit_alter": "racf:gaudaltr", + "base:global_audit_control": "racf:gaudcntl", + "base:global_audit_none": "racf:gaudnone", + "base:global_audit_read": "racf:gaudread", + "base:global_audit_update": "racf:gaudupdt", "base:level": "racf:level", - "base:lrefdat": "racf:lrefdat", - "base:member": "racf:member", - "base:noracf": "racf:noracf", - "base:notify": "racf:notify", - "base:noyourac": "racf:noyourac", + "base:member_resources": "racf:member", + "base:notify_userid": "racf:notify", "base:owner": "racf:owner", - "base:profile": "racf:profile", - "base:raudit": "racf:raudit", - "base:resgroup": "racf:resgroup", - "base:rgaudit": "racf:rgaudit", - "base:seclabel": "racf:seclabel", - "base:seclevel": "racf:seclevel", - "base:singldsn": "racf:singldsn", - "base:stats": "racf:stats", - "base:timezone": "racf:timezone", - "base:tvtoc": "racf:tvtoc", + "base:profile": "racf:profile", # Not documented... + "base:security_label": "racf:seclabel", + "base:security_level": "racf:seclevel", + "base:single_data_set_tape_volume": "racf:singldsn", + "base:time_zone": "racf:timezone", + "base:tape_vtoc": "racf:tvtoc", "base:universal_access": "racf:uacc", - "base:volume": "racf:volume", - "base:warning": "racf:warning", - "base:whendays": "racf:whendays", - "base:whentime": "racf:whentime", + "base:volumes": "racf:volume", + "base:warn_on_insufficient_access": "racf:warning", + "base:terminal_access_allowed_days": "racf:whendays", + "base:terminal_access_allowed_time": "racf:whentime", }, "cdtinfo": { - "cdtinfo:cdtcase": "case", - "cdtinfo:cdtdftrc": "defaultrc", - "cdtinfo:cdtfirst": "first", - "cdtinfo:cdtgen": "generic", - "cdtinfo:cdtgenl": "genlist", - "cdtinfo:cdtgroup": "grouping", - "cdtinfo:cdtkeyql": "keyqual", - "cdtinfo:cdtmac": "macprocessing", - "cdtinfo:cdtmaxln": "maxlenx", - "cdtinfo:cdtmaxlx": "maxlength", - "cdtinfo:cdtmembr": "member", - "cdtinfo:cdtoper": "operations", - "cdtinfo:cdtother": "other", - "cdtinfo:cdtposit": "posit", - "cdtinfo:cdtprfal": "profilesallowed", - "cdtinfo:cdtracl": "raclist", - "cdtinfo:cdtsigl": "signal", - "cdtinfo:cdtslreq": "seclabelrequired", - "cdtinfo:cdtuacc": "defaultuacc", + "cdtinfo:mixed_case_allowed": "case", + "cdtinfo:default_racroute_return_code": "defaultrc", + "cdtinfo:valid_first_characters": "first", + "cdtinfo:generic": "generic", + "cdtinfo:setropts_genlist_allowed": "genlist", + "cdtinfo:grouping_class_name": "grouping", + "cdtinfo:key_qualifiers": "keyqual", + "cdtinfo:manditory_access_control_processing": "macprocessing", + "cdtinfo:max_length": "maxlenx", + "cdtinfo:max_length_racroute": "maxlength", + "cdtinfo:member_class": "member", + "cdtinfo:operations": "operations", + "cdtinfo:valid_other_characters": "other", + "cdtinfo:posit_number": "posit", + "cdtinfo:profiles_allowed": "profilesallowed", + "cdtinfo:raclist_allowed": "raclist", + "cdtinfo:send_enf_signal_on_profile_creation": "signal", + "cdtinfo:security_label_required": "seclabelrequired", + "cdtinfo:default_universal_access": "defaultuacc", }, "cfdef": { "cfdef:cfdtype": "type", - "cfdef:cffirst": "first", - "cfdef:cfhelp": "help", - "cfdef:cflist": "listhead", - "cfdef:cfmixed": "mixed", - "cfdef:cfmnval": "minvalue", - "cfdef:cfmxlen": "maxlength", - "cfdef:cfmxval": "other", - "cfdef:cfother": "other", - "cfdef:cfvalrx": "racf:cfvalrx", + "cfdef:valid_first_characters": "first", + "cfdef:help_text": "help", + "cfdef:list_heading_text": "listhead", + "cfdef:mixed_case_allowed": "mixed", + "cfdef:min_numeric_value": "minvalue", + "cfdef:max_field_length": "maxlength", + "cfdef:max_numeric_value": "other", # I think this is wrong... + "cfdef:valid_other_characters": "other", + "cfdef:validation_rexx_exec": "racf:cfvalrx", }, "dlfdata": { - "dlfdata:jobname": "racf:jobname", + "dlfdata:job_names": "racf:jobname", "dlfdata:retain": "racf:retain", }, "eim": { - "eim:domaindn": "domaindn", - "eim:kerbreg": "kerberg", - "eim:localreg": "localreg", + "eim:domain_distinguished_name": "domaindn", + "eim:kerberos_registry": "kerberg", + "eim:local_registry": "localreg", "eim:options": "options", - "eim:x509reg": "X509reg", + "eim:x509_registry": "X509reg", }, "kerb": { - "kerb:chkaddrs": "checkaddrs", - "kerb:deftktlf": "deftktlife", - "kerb:encrypt": "encrypt", - "kerb:kerbname": "kerbname", - "kerb:keyvers": "racf:keyvers", - "kerb:maxtktlf": "maxtktlf", - "kerb:mintktlf": "mintklife", + "kerb:validate_addresses": "checkaddrs", + "kerb:default_ticket_life": "deftktlife", + "kerb:encryption_algorithm": "encrypt", + "kerb:realm_name": "kerbname", + "kerb:max_ticket_life": "maxtktlf", + "kerb:min_ticket_life": "mintklife", "kerb:password": "password", }, "icsf": { - "icsf:crtlbls": "symexportcert", - "icsf:export": "symexportable", - "icsf:keylbls": "symexportkey", - "icsf:scpwrap": "symcpacfwrap", - "icsf:scpret": "symcpacfret", - "icsf:usage": "asymusage", + "icsf:symmetric_export_certificates": "symexportcert", + "icsf:exportable_public_keys": "symexportable", + "icsf:symmetric_export_public_keys": "symexportkey", + "icsf:symmetric_cpacf_rewrap": "symcpacfwrap", + "icsf:symmetric_cpacf_rewrap_return": "symcpacfret", + "icsf:asymetric_key_usage": "asymusage", }, "ictx": { - "ictx:domap": "domap", - "ictx:mapreq": "mapreq", - "ictx:maptimeo": "maptimeo", - "ictx:usemap": "usemap", + "ictx:use_eim": "domap", + "ictx:require_identity_mapping": "mapreq", + "ictx:identity_map_timeout": "maptimeo", + "ictx:cache_application_provided_identity_map": "usemap", }, "idtparms": { - "idtpamrs:sigtoken": "sigtoken", - "idtparms:sigseqn": "sigseqnum", - "idtparms:sigcat": "sigcat", - "idtparms:sigalg": "sigalg", - "idtparms:idttimeo": "idttimeout", - "idtpamrs:anyappl": "anyappl", + "idtparms:token": "sigtoken", + "idtparms:sequence_number": "sigseqnum", + "idtparms:category": "sigcat", + "idtparms:signature_algorithm": "sigalg", + "idtparms:identity_token_timeout": "idttimeout", + "idtparms:use_for_any_application": "anyappl", }, - "jes": {"jes:keylabel": "racf:keylabel"}, + "jes": {"jes:key_label": "racf:keylabel"}, "mfpolicy": { "mfpolicy:factors": "racf:factors", - "mfpolicy:timeout": "racf:timeout", - "mfpolicy:reuse": "racf:reuse", + "mfpolicy:token_timeout": "racf:timeout", + "mfpolicy:reuse_token": "racf:reuse", }, "proxy": { - "proxy:binddn": "binddn", - "proxy:bindpw": "bindpw", - "proxy:ldaphost": "ldaphost", + "proxy:bind_distinguished_name": "binddn", + "proxy:bind_password": "bindpw", + "proxy:ldap_host": "ldaphost", }, "session": { - "session:convsec": "racf:convsec", - "session:interval": "racf:interval", - "session:lock": "racf:lock", - "session:sesskey": "racf:sesskey", + "session:security_checking_level": "racf:convsec", + "session:session_key_interval": "racf:interval", + "session:locked": "racf:lock", + "session:session_key": "racf:sesskey", }, "sigver": { - "sigver:failload": "failload", - "sigver:sigaudit": "sigaudit", - "sigver:sigreqd": "sigrequired", + "sigver:fail_program_load_condition": "failload", + "sigver:log_signature_verification_events": "sigaudit", + "sigver:signature_required": "sigrequired", }, "ssignon": { - "ssigon:keycrypt": "racf:keycrypt", - "ssigon:ptkeylab": "ptkeylab", - "ssigon:pttype": "pttype", - "ssigon:pttimeo": "pttimeo", - "ssigon:ptreplay": "ptreplay", - "ssigon:keylabel": "racf:keylabel", - "ssigno:keymask": "racf:keymask", + "ssignon:encrypt_legacy_pass_ticket_key": "racf:keycrypt", + "ssignon:enhanced_pass_ticket_label": "ptkeylab", + "ssignon:enhanced_pass_ticket_type": "pttype", + "ssignon:enhanced_pass_ticket_timeout": "pttimeo", + "ssignon:enhanced_pass_ticket_replay": "ptreplay", + "ssignon:legacy_pass_ticket_label": "racf:keylabel", + "ssignon:mask_legacy_pass_ticket_key": "racf:keymask", }, "stdata": { - "ssigon:group": "racf:group", - "ssigon:privlege": "racf:privlege", - "ssigon:trace": "racf:trace", - "ssigon:trusted": "racf:trusted", - "ssigon:user": "racf:user", + "stdata:group": "racf:group", + "stdata:privileged": "racf:privlege", + "stdata:trace": "racf:trace", + "stdata:trusted": "racf:trusted", + "stdata:user": "racf:user", + }, + "svfmr": { + "svfmr:parameter_list": "racf:parmname", + "svfmr:script": "racf:script", }, - "svfmr": {"svfmr:parmname": "racf:parmname", "svfmr:script": "racf:script"}, "tme": { "tme:children": "racf:children", "tme:groups": "racf:groups", diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 5f47b071..e2b4824f 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -20,88 +20,88 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:active_class": "racf:classact", - "base:addcreat": "racf:addcreat", - "base:adsp": "racf:adsp", - "base:applaudt": "racf:applaudt", - "base:audit_class": "racf:audit", - "base:catdsns": "racf:catdsns", - "base:cmdviol": "racf:cmdviol", - "base:compmode": "racf:compmode", - "base:egn": "racf:egn", - "base:erase": "racf:erase", - "base:eraseall": "racf:eraseall", - "base:erasesec": "racf:erasesec", - "base:general_command_class": "racf:gencmd", - "base:generic_profile_checking_class": "racf:generic", - "base:generic_profile_sharing_class": "racf:genlist", - "base:genowner": "racf:genowner", - "base:global_access_class": "racf:global", - "base:grplist": "racf:grplist", - "base:history": "racf:history", - "base:inactive": "racf:inactive", - "base:initstat": "racf:initstat", - "base:interval": "racf:interval", - "base:jesbatch": "racf:jesbatch", - "base:jesearly": "racf:jesearly", - "base:jesnje": "racf:jesnje", - "base:jesundef": "racf:jesundef", - "base:jesxbm": "racf:jesxbm", - "base:kerblvl": "racf:kerblvl", + "base:active_classes": "racf:classact", + "base:add_creator": "racf:addcreat", + "base:automatic_data_set_protection": "racf:adsp", + "base:application_logon_auditing": "racf:applaudt", + "base:audit_classes": "racf:audit", + "base:uncataloged_data_set_access": "racf:catdsns", + "base:log_racf_command_violations": "racf:cmdviol", + "base:security_label_compatibility_mode": "racf:compmode", + "base:enhanced_generic_naming": "racf:egn", + "base:erase_data_sets_on_delete": "racf:erase", + "base:erase_data_sets_on_delete_all": "racf:eraseall", + "base:erase_data_sets_on_delete_security_level": "racf:erasesec", + "base:general_command_classes": "racf:gencmd", + "base:generic_profile_checking_classes": "racf:generic", + "base:generic_profile_sharing_classes": "racf:genlist", + "base:generic_owner": "racf:genowner", + "base:global_access_classes": "racf:global", + "base:list_of_groups_access_checking": "racf:grplist", + "base:password_history": "racf:history", + "base:revoke_inactive_userids_interval": "racf:inactive", + "base:record_user_verification_statistics": "racf:initstat", + "base:max_password_change_interval": "racf:interval", + "base:jes_batch": "racf:jesbatch", + "base:jes_early_verification": "racf:jesearly", + "base:jes_network_user": "racf:jesnje", + "base:jes_undefined_user": "racf:jesundef", + "base:jes_execution_batch_monitoring": "racf:jesxbm", + "base:kerberos_encryption_level": "racf:kerblvl", "base:list": "racf:list", - "base:logalwys": "racf:logalwys", - "base:logdeflt": "racf:logdeflt", - "base:logfail": "racf:logfail", - "base:lognever": "racf:lognever", - "base:logsucc": "racf:logsucc", - "base:minchang": "racf:minchang", - "base:mixdcase": "racf:mixdcase", - "base:mlactive": "racf:mlactive", - "base:mlfs": "racf:mlfs", - "base:mlipc": "racf:mlipc", - "base:mlnames": "racf:mlnames", - "base:mlquiet": "racf:mlquiet", - "base:mls": "racf:mls", - "base:mlstable": "racf:mlstable", - "base:model": "racf:model", - "base:modgdg": "racf:modgdg", - "base:modgroup": "racf:modgroup", - "base:moduser": "racf:moduser", - "base:operaudt": "racf:operaudt", - "base:phrint": "racf:phrint", - "base:prefix": "racf:prefix", - "base:primlang": "racf:primlang", - "base:protall": "racf:protall", - "base:pwdalg": "racf:pwdalg", - "base:pwdspec": "racf:pwdspec", + "base:audit_log_always_classes": "racf:logalwys", + "base:audit_log_default_classes": "racf:logdeflt", + "base:audit_log_failure_classses": "racf:logfail", + "base:audit_log_never_classse": "racf:lognever", + "base:audit_log_success_classes": "racf:logsucc", + "base:min_password_change_interval": "racf:minchang", + "base:mixed_case_password_support": "racf:mixdcase", + "base:multi_level_security_address_space": "racf:mlactive", + "base:multi_level_security_file_system": "racf:mlfs", + "base:multi_level_security_interprocess": "racf:mlipc", + "base:multi_level_security_file_names": "racf:mlnames", + "base:multi_level_security_logon": "racf:mlquiet", + "base:multi_level_security_declassification": "racf:mls", + "base:multi_level_security_label_alteration": "racf:mlstable", + "base:profile_modelling": "racf:model", + "base:profile_modelling_generation_data_group": "racf:modgdg", + "base:profile_modelling_group": "racf:modgroup", + "base:profile_modelling_user": "racf:moduser", + "base:log_operator_actions": "racf:operaudt", + "base:passphrase_change_interval": "racf:phrint", + "base:data_set_single_level_name_prefix_protection": "racf:prefix", + "base:primary_language": "racf:primlang", + "base:protect_all_data_sets": "racf:protall", + "base:password_encryption_algorithm": "racf:pwdalg", + "base:special_character_password_support": "racf:pwdspec", "base:raclist": "racf:raclist", - "base:realdsn": "racf:realdsn", + "base:log_real_data_set_name": "racf:realdsn", "base:refresh": "racf:refresh", - "base:retpd": "racf:retpd", - "base:revoke": "racf:revoke", - "base:rules": "racf:rules", - "base:rule1": "racf:rule1", - "base:rule2": "racf:rule2", - "base:rule3": "racf:rule3", - "base:rule4": "racf:rule4", - "base:rule5": "racf:rule5", - "base:rule6": "racf:rule6", - "base:rule7": "racf:rule7", - "base:rule8": "racf:rule8", - "base:rvarswpw": "racf:rvarswpw", - "base:rvarstpw": "racf:rvarstpw", - "base:saudit": "racf:saudit", - "base:seclabct": "racf:seclabct", - "base:seclang": "racf:seclang", - "base:sessint": "racf:sessint", - "base:slabaudt": "racf:slabaudt", - "base:slbysys": "racf:slbysys", - "base:slevaudt": "racf:slevaudt", - "base:statistics_class": "racf:classtat", - "base:tapedsn": "racf:tapedsn", - "base:terminal": "racf:terminal", - "base:warning": "racf:warning", - "base:whenprog": "racf:whenprog", + "base:tape_data_set_security_retention_period": "racf:retpd", + "base:max_incorrect_password_attempts": "racf:revoke", + "base:password_rules": "racf:rules", + "base:password_rule_1": "racf:rule1", + "base:password_rule_2": "racf:rule2", + "base:password_rule_3": "racf:rule3", + "base:password_rule_4": "racf:rule4", + "base:password_rule_5": "racf:rule5", + "base:password_rule_6": "racf:rule6", + "base:password_rule_7": "racf:rule7", + "base:password_rule_8": "racf:rule8", + "base:rvary_switch_password": "racf:rvarswpw", + "base:rvary_status_password": "racf:rvarstpw", + "base:log_commands_issuesd_by_special_users": "racf:saudit", + "base:security_label_control": "racf:seclabct", + "base:secondary_language": "racf:seclang", + "base:session_key_verification_interval": "racf:sessint", + "base:security_label_auditing": "racf:slabaudt", + "base:security_label_system": "racf:slbysys", + "base:security_level_auditing": "racf:slevaudt", + "base:statistics_classes": "racf:classtat", + "base:tape_data_set_protection": "racf:tapedsn", + "base:terminal_universal_access": "racf:terminal", + "base:password_expiration_warning": "racf:warning", + "base:program_control": "racf:whenprog", } } super().__init__( @@ -149,12 +149,12 @@ def get_class_attributes(self, class_name: str) -> Union[list, bytes]: # ============================================================================ def add_audit_class(self, class_name: str) -> Union[dict, bytes]: """Add a class to list of classes that RACF performs auditing for.""" - result = self.alter(options={"base:audit_class": class_name}) + result = self.alter(options={"base:audit_classes": class_name}) return self._to_steps(result) def remove_audit_class(self, class_name: str) -> Union[dict, bytes]: """Remove a class from the list of classes that RACF performs auditing for.""" - result = self.alter(options={"delete:base:audit_class": class_name}) + result = self.alter(options={"delete:base:audit_classes": class_name}) return self._to_steps(result) # ============================================================================ @@ -164,7 +164,7 @@ def add_active_class(self, class_name: str) -> Union[dict, bytes]: """ Add a class to the list of classes that RACF performs access authorization checking for. """ - result = self.alter(options={"base:active_class": class_name}) + result = self.alter(options={"base:active_classes": class_name}) return self._to_steps(result) def remove_active_class(self, class_name: str) -> Union[dict, bytes]: @@ -172,7 +172,7 @@ def remove_active_class(self, class_name: str) -> Union[dict, bytes]: Remove a class from the list of classes that RACF performs access authorization checking for. """ - result = self.alter(options={"delete:base:active_class": class_name}) + result = self.alter(options={"delete:base:active_classes": class_name}) return self._to_steps(result) # ============================================================================ @@ -180,12 +180,12 @@ def remove_active_class(self, class_name: str) -> Union[dict, bytes]: # ============================================================================ def add_statistics_class(self, class_name: str) -> Union[dict, bytes]: """Add a class to the list of classes that RACF collects statistics for.""" - result = self.alter(options={"base:statistics_class": class_name}) + result = self.alter(options={"base:statistics_classes": class_name}) return self._to_steps(result) def remove_statistics_class(self, class_name: str) -> Union[dict, bytes]: """Remove a class from the list of classes that RACF collects statistics for.""" - result = self.alter(options={"delete:base:statistics_class": class_name}) + result = self.alter(options={"delete:base:statistics_classes": class_name}) return self._to_steps(result) # ============================================================================ @@ -198,7 +198,7 @@ def add_generic_command_processing_class( Add a class to the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"base:general_command_class": class_name}) + result = self.alter(options={"base:general_command_classes": class_name}) return self._to_steps(result) def remove_generic_command_processing_class( @@ -208,7 +208,7 @@ def remove_generic_command_processing_class( Remove a class from the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"delete:base:general_command_class": class_name}) + result = self.alter(options={"delete:base:general_command_classes": class_name}) return self._to_steps(result) # ============================================================================ @@ -216,7 +216,9 @@ def remove_generic_command_processing_class( # ============================================================================ def add_generic_profile_checking_class(self, class_name: str) -> Union[dict, bytes]: """Add a class to the list of classes that have generic profile checking enabled.""" - result = self.alter(options={"base:generic_profile_checking_class": class_name}) + result = self.alter( + options={"base:generic_profile_checking_classes": class_name} + ) return self._to_steps(result) def remove_generic_profile_checking_class( @@ -224,7 +226,7 @@ def remove_generic_profile_checking_class( ) -> Union[dict, bytes]: """Remove a class from the list of classes that have generic profile checking enabled.""" result = self.alter( - options={"delete:base:generic_profile_checking_class": class_name} + options={"delete:base:generic_profile_checking_classes": class_name} ) return self._to_steps(result) @@ -236,7 +238,9 @@ def add_generic_profile_sharing_class(self, class_name: str) -> Union[dict, byte Add a class to the list of classes that are eligible for general resource profile sharing in common storage. """ - result = self.alter(options={"base:generic_profile_sharing_class": class_name}) + result = self.alter( + options={"base:generic_profile_sharing_classes": class_name} + ) return self._to_steps(result) def remove_generic_profile_sharing_class( @@ -247,7 +251,7 @@ def remove_generic_profile_sharing_class( for general resource profile sharing in common storage. """ result = self.alter( - options={"delete:base:generic_profile_sharing_class": class_name} + options={"delete:base:generic_profile_sharing_classes": class_name} ) return self._to_steps(result) @@ -256,11 +260,11 @@ def remove_generic_profile_sharing_class( # ============================================================================ def add_global_access_class(self, class_name: str) -> Union[dict, bytes]: """Add a class to the list of classes eligible for global access checking.""" - return self.alter(options={"base:global_access_class": class_name}) + return self.alter(options={"base:global_access_classes": class_name}) def remove_global_access_class(self, class_name: str) -> Union[dict, bytes]: """Remove a class from the list of classes eligible for global access checking.""" - result = self.alter(options={"delete:base:global_access_class": class_name}) + result = self.alter(options={"delete:base:global_access_classes": class_name}) return self._to_steps(result) # ============================================================================ @@ -506,7 +510,7 @@ def _format_profile(self, result: dict) -> None: for key_raw, value_raw in profile_raw: if "[TOKEN " in value_raw: (key_raw, value_raw) = self.__fix_key_value_raw(key_raw, value_raw) - key = self._profile_field_to_camel_case(key_raw.lower()) + key = self._profile_field_to_camel_case("base", key_raw.lower()) if key_raw == "ATTRIBUTES": self.__add_attributes(profile, key, value_raw) continue @@ -578,7 +582,7 @@ def __add_attributes(self, profile: dict, key: str, value_raw: str): attribute = "LOG COMMAND VIOLATIONS" case "OPERAUDIT": attribute = "OPERATIONS AUDIT" - attribute = self._profile_field_to_camel_case(attribute.lower()) + attribute = self._profile_field_to_camel_case("base", attribute.lower()) profile[key][attribute] = value def __to_list(self, value_raw: str, n: int = 1) -> List[str]: @@ -685,7 +689,7 @@ def __add_generic_subfield( subkey_raw = key_raw.replace(subfield_token, "") if key not in profile: profile[key] = {} - subkey = self._profile_field_to_camel_case(subkey_raw.lower()) + subkey = self._profile_field_to_camel_case("base", subkey_raw.lower()) if subdictionary: profile[key][subkey] = subdictionary else: @@ -697,7 +701,9 @@ def __process_generic_subsubfield_options(self, subsubfield_options: str) -> dic options_dictionary = {} for option in subsubfield_option_tokens: option_tokens = option.split("=") - key = self._profile_field_to_camel_case(option_tokens[0].strip().lower()) + key = self._profile_field_to_camel_case( + "base", option_tokens[0].strip().lower() + ) value = self._cast_from_str(option_tokens[1].strip()) options_dictionary[key] = value return options_dictionary diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 0984979c..3b5f6460 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -20,194 +20,182 @@ def __init__( ) -> None: self._valid_segment_traits = { "base": { - "base:adsp": "racf:adsp", + "base:automatic_data_set_protection": "racf:adsp", "base:auditor": "racf:auditor", - "base:auth": "racf:auth", - "base:category": "racf:category", + "base:default_group_authority": "racf:auth", + "base:security_categories": "racf:category", "base:class_authorizations": "racf:clauth", - "base:connects": "racf:connects", - "base:cadsp": "racf:cadsp", - "base:cauditor": "racf:cauditor", - "base:cauthda": "racf:cauthda", - "base:cgroup": "racf:cgroup", - "base:cgrpacc": "racf:cgrpacc", - "base:cinitct": "racf:cinitct", - "base:cljdate": "racf:cljdate", - "base:cljtime": "racf:cljtime", - "base:coper": "racf:coper", - "base:cowner": "racf:cowner", - "base:cresume": "racf:cresume", - "base:crevoke": "racf:crevoke", - "base:crevokfl": "racf:crevokfl", - "base:cspecial": "racf:cspecial", - "base:cuacc": "racf:cuacc", - "base:creatdat": "racf:creatdat", - "base:data": "racf:data", - "base:dfltgrp": "defgroup", - "base:expired": "racf:expired", - "base:factorn": "racf:factorn", - "base:factor": "racf:factor", - "base:facactv": "racf:facactv", - "base:factagnn": "racf:factagnn", - "base:facvalnn": "racf:facvalnn", + "base:installation_data": "racf:data", + "base:default_group": "defgroup", + "base:password_expired": "racf:expired", "base:group": "racf:group", - "base:grpacc": "racf:grpacc", - "base:hasphras": "racf:hasphras", - "base:haspwd": "racf:haspwd", - "base:lastdate": "racf:lastdate", - "base:lasttime": "racf:lasttime", - "base:mfaflbk": "racf:mfaflbk", - "base:mfapolnm": "racf:mfapolnm", - "base:model": "racf:model", + "base:group_data_set_access": "racf:grpacc", + "base:model_data_set": "racf:model", "base:name": "name", - "base:oidcard": "racf:oidcard", + "base:require_operator_id_card": "racf:oidcard", "base:operations": "racf:oper", "base:owner": "racf:owner", - "base:passdate": "racf:passdate", - "base:passint": "racf:passint", "base:password": "racf:password", "base:passphrase": "racf:phrase", - "base:phrdate": "racf:phrdate", - "base:phrint": "racf:phrint", - "base:pphenv": "racf:pphenv", - "base:protectd": "racf:protectd", - "base:pwdenv": "racf:pwdenv", - "base:rest": "racf:rest", + "base:restrict_global_access_checking": "racf:rest", "base:resume": "resumedate", "base:revoke": "revokedate", - "base:revokefl": "racf:revokefl", - "base:roaudit": "racf:roaudit", - "base:seclabel": "seclabel", - "base:seclevel": "racf:seclevel", + "base:audit_responsibility": "racf:roaudit", + "base:security_label": "seclabel", + "base:security_level": "racf:seclevel", "base:special": "racf:special", - "base:uacc": "racf:uacc", - "base:uaudit": "uaudit", - "base:whendays": "whendays", - "base:whensrv": "whensrv", - "base:whentime": "whentime", + "base:universal_access": "racf:uacc", + "base:audit_logging": "uaudit", + "base:logon_allowed_days": "whendays", + "base:logon_allowed_time": "whentime", }, "cics": { - "cisc:opclass": "racf:opclass", - "cics:opident": "opident", - "cics:opprty": "opprty", - "cics:rslkey": "racf:rslkey", + "cics:operator_classes": "racf:opclass", + "cics:operator_id": "opident", + "cics:operator_priority": "opprty", + "cics:rsl_key": "racf:rslkey", "cics:timeout": "timeout", - "cics:tslkey": "racf:tslkey", - "cics:xrfsoff": "force", + "cics:tsl_key": "racf:tslkey", + "cics:xrf_sign_off": "force", }, "dce": { - "dce:autolog": "autolog", - "dce:dcename": "dcename", - "dce:homecell": "homecell", - "dce:homeuuid": "homeuuid", + "dce:auto_login": "autolog", + "dce:name": "dcename", + "dce:home_cell": "homecell", + "dce:home_cell_uuid": "homeuuid", "dce:uuid": "uuid", }, "dfp": { - "dfp:dataappl": "dataappl", - "dfp:dataclas": "dataclas", - "dfp:mgmtclas": "mgmtclass", - "dfp:storclas": "storclas", + "dfp:data_application": "dataappl", + "dfp:data_class": "dataclas", + "dfp:management_class": "mgmtclass", + "dfp:storage_class": "storclas", }, - "eim": {"ldapprof": "racf:ldapprof"}, + "eim": {"eim:ldap_bind_profile": "racf:ldapprof"}, "kerb": { - "dfp:encrypt": "racf:encrypt", - "dfp:kerbname": "racf:kerbname", - "dfp:keyfrom": "racf:keyfrom", - "dfp:keyvers": "racf:keyvers", - "dfp:maxtktlf": "racf:maxtktlf", + "kerb:encryption_algorithm": "racf:encrypt", + "kerb:name": "racf:kerbname", + "kerb:max_ticket_life": "racf:maxtktlf", }, - "language": {"language:primary": "primary", "language:second": "secondary"}, - "lnotes": {"lnotes:sname": "racf:sname"}, + "language": { + "language:primary": "primary", + "language:secondary": "secondary", + }, + "lnotes": {"lnotes:zos_short_name": "racf:sname"}, "mfa": { "mfa:factor": "racf:factor", - "mfa:facactv": "racf:facactv", - "mfa:factags": "racf:factags", - "mfa:mfaflbk": "racf:mfaflbk", - "mfa:mfapolnm": "racf:mfapolnm", + "mfa:active": "racf:facactv", + "mfa:tags": "racf:factags", + "mfa:password_fallback": "racf:mfaflbk", + "mfa:policy": "racf:mfapolnm", }, - "nds": {"nds:uname": "racf:uname"}, + "nds": {"nds:username": "racf:uname"}, "netview": { - "netview:consname": "consid", - "netview:ctl": "secctl", + "netview:default_console": "consid", + "netview:security_check": "secctl", "netview:domains": "nvdomains", - "netview:ic": "ic", - "netview:msgrecvr": "msgrec", - "netview:ngmfadmn": "racf:ngmfadmn", - "netview:ngmfvspn": "gmfadmin", - "netview:opclass": "racf:opclass", + "netview:logon_commands": "ic", + "netview:recieve_unsolicited_messages": "msgrec", + "netview:graphic_monitor_facility_admin": "racf:ngmfadmn", + "netview:view_span": "gmfadmin", + "netview:operator_scope_classes": "racf:opclass", }, "omvs": { - "omvs:assize": "assize", - "omvs:autouid": "racf:autouid", - "omvs:cputime": "cputime", - "omvs:fileproc": "filemax", - "omvs:home": "home", - "omvs:memlimit": "memlim", - "omvs:mmaparea": "mmaparea", - "omvs:procuser": "procmax", - "omvs:program": "pgm", + "omvs:max_address_space_size": "assize", + "omvs:auto_uid": "racf:autouid", + "omvs:max_cpu_time": "cputime", + "omvs:max_files_per_process": "filemax", + "omvs:home_directory": "home", + "omvs:max_nonshared_memory": "memlim", + "omvs:max_file_mapping_pages": "mmaparea", + "omvs:max_processes": "procmax", + "omvs:default_shell": "pgm", "omvs:shared": "racf:shared", - "omvs:shmemmax": "shmemmax", - "omvs:threads": "threads", + "omvs:max_shared_memory": "shmemmax", + "omvs:max_threads": "threads", "omvs:uid": "uid", }, "operparm": { - "operparm:altgrp": "altgrp", - "operparm:auto": "auto", - "operparm:cmdsys": "cmdsys", - "operparm:dom": "dom", - "operparm:hc": "hc", - "operparm:intids": "intid", - "operparm:key": "key", - "operparm:level": "racf:level", - "operparm:logcmd": "logcmd", - "operparm:mform": "mform", - "operparm:migid": "migid", - "operparm:monitor": "mon", - "operparm:mscope": "racf:mscope", - "operparm:operauth": "auth", - "operparm:routcode": "routcode", - "operparm:storage": "storage", - "operparm:ud": "ud", - "operparm:unknids": "unkids", + "operparm:alternate_console_group": "altgrp", + "operparm:recieve_automated_messages": "auto", + "operparm:command_target_systems": "cmdsys", + "operparm:recieve_delete_operator_messages": "dom", + "operparm:recieve_hardcopy_messages": "hc", + "operparm:recieve_internal_console_messages": "intid", + "operparm:console_searching_key": "key", + "operparm:message_level": "racf:level", + "operparm:log_command_responses": "logcmd", + "operparm:message_format": "mform", + "operparm:migration_id": "migid", + "operparm:events_to_monitor": "mon", + "operparm:message_scope": "racf:mscope", + "operparm:operator_command_authority": "auth", + "operparm:recieve_routing_codes": "routcode", + "operparm:message_queue_storage": "storage", + "operparm:recieve_undelivered_messages": "ud", + "operparm:recieve_messages_from_unknown_console_ids": "unkids", }, "ovm": { - "ovm:fsroot": "racf:fsroot", - "ovm:vhome": "racf:vhome", - "ovm:vprogram": "racf:vprogram", - "ovm:vuid": "racf:vuid", + "ovm:file_system_root": "racf:fsroot", + "ovm:home_directory": "racf:vhome", + "ovm:default_shell": "racf:vprogram", + "ovm:uid": "racf:vuid", }, "proxy": { - "proxy:binddn": "racf:binddn", - "proxy:bindpw": "racf:bindpw", - "proxy:ldaphost": "racf:ldaphost", + "proxy:bind_distinguished_name": "racf:binddn", + "proxy:bind_password": "racf:bindpw", + "proxy:ldap_host": "racf:ldaphost", }, "tso": { - "tso:acctnum": "acctnum", - "tso:command": "command", - "tso:dest": "dest", - "tso:hldclass": "holdclass", - "tso:jobclass": "jobclass", - "tso:maxsize": "maxsize", - "tso:msgclass": "msgclass", - "tso:proc": "proc", - "tso:seclabel": "seclabel", - "tso:size": "size", - "tso:sysoutcl": "sysclass", - "tso:unit": "unit", - "tso:userdata": "userdata", + "tso:account_number": "acctnum", + "tso:logon_command": "command", + "tso:sysout_destination_id": "dest", + "tso:hold_class": "holdclass", + "tso:job_class": "jobclass", + "tso:max_region_size": "maxsize", + "tso:message_class": "msgclass", + "tso:logon_procedure": "proc", + "tso:security_label": "seclabel", + "tso:region_size": "size", + "tso:sysout_class": "sysclass", + "tso:data_set_allocation_unit": "unit", + "tso:user_data": "userdata", }, "workattr": { - "workattr:waaccnt": "waaccnt", - "workattr:waaddr1": "waaddr1", - "workattr:waaddr2": "waaddr2", - "workattr:waaddr3": "waaddr3", - "workattr:waaddr4": "waaddr4", - "workattr:wabldg": "wabldg", - "workattr:wadept": "wadept", - "workattr:waname": "waname", - "workattr:waroom": "waroom", - "workattr:waemail": "waemail", + "workattr:account_number": "waaccnt", + "workattr:sysout_address_1": "waaddr1", + "workattr:sysout_address_2": "waaddr2", + "workattr:sysout_address_3": "waaddr3", + "workattr:sysout_address_4": "waaddr4", + "workattr:sysout_building": "wabldg", + "workattr:sysout_department": "wadept", + "workattr:sysout_user": "waname", + "workattr:sysout_room": "waroom", + "workattr:sysout_email": "waemail", + }, + } + self._extracted_key_value_pair_segment_traits_map = { + "omvs": { + "home": "homeDirectory", + "program": "defaultShell", + "cputimemax": "maxCpuTime", + "assizemax": "maxAddressSpaceSize", + "fileprocmax": "maxFilesPerProcess", + "procusermax": "maxProcesses", + "threadsmax": "maxThreads", + "mmapareamax": "maxFileMappingPages", + }, + "tso": { + "acctnum": "accountNumber", + "jobclass": "jobClass", + "msgclass": "messageClass", + "proc": "procedure", + "size": "regionSize", + "maxsize": "maxRegionSize", + "sysoutclass": "sysoutClass", + "unit": "dataSetAllocationUnit", + "userdata": "userData", + "command": "logonCommand", }, } super().__init__( @@ -361,35 +349,35 @@ def set_omvs_uid(self, userid: str, uid: int) -> Union[dict, bytes]: # ============================================================================ # OMVS Home # ============================================================================ - def get_omvs_home(self, userid: str) -> Union[str, None, bytes]: + def get_omvs_home_directory(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS home directory.""" profile = self.extract(userid, segments={"omvs": True}, profile_only=True) - return self._get_field(profile, "omvs", "home") + return self._get_field(profile, "omvs", "homeDirectory") - def set_omvs_home( + def set_omvs_home_directory( self, userid: str, home_directory: str, ) -> Union[dict, bytes]: """Set a user's OMVS home directory.""" - result = self.alter(userid, traits={"omvs:home": home_directory}) + result = self.alter(userid, traits={"omvs:home_directory": home_directory}) return self._to_steps(result) # ============================================================================ # OMVS Program # ============================================================================ - def get_omvs_program(self, userid: str) -> Union[str, None, bytes]: + def get_omvs_default_shell(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS program.""" profile = self.extract(userid, segments={"omvs": True}, profile_only=True) - return self._get_field(profile, "omvs", "program") + return self._get_field(profile, "omvs", "defaultShell") - def set_omvs_program( + def set_omvs_default_shell( self, userid: str, program: str, ) -> Union[dict, bytes]: """Set a user's OMVS program.""" - result = self.alter(userid, traits={"omvs:program": program}) + result = self.alter(userid, traits={"omvs:default_shell": program}) return self._to_steps(result) # ============================================================================ diff --git a/tests/common/test_logger.py b/tests/common/test_logger.py new file mode 100644 index 00000000..82e5cd0a --- /dev/null +++ b/tests/common/test_logger.py @@ -0,0 +1,32 @@ +"""Test the pyRACF logger.""" + +import unittest + +import __init__ + +from pyracf.common.logger import Logger + +# Resolves F401 +__init__ + + +class TestLogger(unittest.TestCase): + logger = Logger() + + def test_logger_can_redact_secrets_from_result_xml(self): + secret_traits = {"segment:trait": "namespace:secret"} + unredacted_xml = "textSECRET (secret)" + redacted_xml_expected = "textSECRET (********)" + redacted_xml_actual = self.logger.redact_result_xml( + unredacted_xml, secret_traits + ) + self.assertEqual(redacted_xml_actual, redacted_xml_expected) + + def test_logger_can_redact_secrets_from_result_xml_trailing_space(self): + secret_traits = {"segment:trait": "namespace:secret"} + unredacted_xml = "textSECRET (secret) " + redacted_xml_expected = "textSECRET (********) " + redacted_xml_actual = self.logger.redact_result_xml( + unredacted_xml, secret_traits + ) + self.assertEqual(redacted_xml_actual, redacted_xml_expected) diff --git a/tests/test_runner.py b/tests/test_runner.py index 4d6b7ede..8b240d9c 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -8,6 +8,7 @@ from tests.access.test_access_debug_logging import TestAccessDebugLogging from tests.access.test_access_request_builder import TestAccessRequestBuilder from tests.access.test_access_result_parser import TestAccessResultParser +from tests.common.test_logger import TestLogger from tests.connection.test_connection_debug_logging import TestConnectionDebugLogging from tests.connection.test_connection_request_builder import ( TestConnectionRequestBuilder, @@ -52,6 +53,7 @@ def __test_suite() -> unittest.TestSuite: TestAccessResultParser, TestAccessRequestBuilder, TestAccessDebugLogging, + TestLogger, TestConnectionResultParser, TestConnectionRequestBuilder, TestConnectionSetters, diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 4213b47c..75a12aa1 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -114,8 +114,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "base:special": True, "base:operator": False, "omvs:uid": "2424", - "omvs:home": "/u/squidwrd", - "omvs:program": "/bin/sh", + "omvs:home_directory": "/u/squidwrd", + "omvs:default_shell": "/bin/sh", } TEST_ADD_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ADD_USER_REQUEST_TRAITS) TEST_ADD_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF" @@ -136,8 +136,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_USER_REQUEST_TRAITS = { "base:special": False, "base:operator": True, - "omvs:home": "/u/clarinet", - "omvs:program": False, + "omvs:home_directory": "/u/clarinet", + "omvs:default_shell": False, } # Extract User @@ -191,8 +191,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "user_set_class_authorizations_request.xml" ) TEST_USER_SET_OMVS_UID_XML = get_sample("user_set_omvs_uid_request.xml") -TEST_USER_SET_OMVS_HOME_XML = get_sample("user_set_omvs_home_request.xml") -TEST_USER_SET_OMVS_PROGRAM_XML = get_sample("user_set_omvs_program_request.xml") +TEST_USER_SET_OMVS_HOME_DIRECTORY_XML = get_sample( + "user_set_omvs_home_directory_request.xml" +) +TEST_USER_SET_OMVS_DEFAULT_SHELL_XML = get_sample( + "user_set_omvs_default_shell_request.xml" +) # ============================================================================ # Debug Logging @@ -233,8 +237,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Alter User Traits TEST_ALTER_USER_CSDATA_REQUEST_TRAITS = { "base:special": False, - "omvs:home": "/u/clarinet", - "omvs:program": False, + "omvs:home_directory": "/u/clarinet", + "omvs:default_shell": False, "csdata:tstcsfld": "testval", } diff --git a/tests/user/test_user_getters.py b/tests/user/test_user_getters.py index 089a43bf..24313b68 100644 --- a/tests/user/test_user_getters.py +++ b/tests/user/test_user_getters.py @@ -199,16 +199,18 @@ def test_user_admin_get_omvs_uid_returns_none_when_no_omvs_segment_exists( # ============================================================================ # OMVS Home # ============================================================================ - def test_user_admin_get_omvs_home_works( + def test_user_admin_get_omvs_home_directory_works( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML ) - self.assertEqual(self.user_admin.get_omvs_home("squidwrd"), "/u/squidwrd") + self.assertEqual( + self.user_admin.get_omvs_home_directory("squidwrd"), "/u/squidwrd" + ) - def test_user_admin_get_omvs_home_raises_an_exception_when_extract_fails( + def test_user_admin_get_omvs_home_directory_raises_an_exception_when_extract_fails( self, call_racf_mock: Mock, ): @@ -216,30 +218,30 @@ def test_user_admin_get_omvs_home_raises_an_exception_when_extract_fails( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError): - self.user_admin.get_omvs_home("squidwrd") + self.user_admin.get_omvs_home_directory("squidwrd") - def test_user_admin_get_omvs_home_returns_none_when_no_omvs_segment_exists( + def test_user_admin_get_omvs_home_directory_returns_none_when_no_omvs_segment_exists( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML ) - self.assertIsNone(self.user_admin.get_omvs_home("squidwrd")) + self.assertIsNone(self.user_admin.get_omvs_home_directory("squidwrd")) # ============================================================================ # OMVS Program # ============================================================================ - def test_user_admin_get_omvs_program_works( + def test_user_admin_get_omvs_default_shell_works( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML ) - self.assertEqual(self.user_admin.get_omvs_program("squidwrd"), "/bin/sh") + self.assertEqual(self.user_admin.get_omvs_default_shell("squidwrd"), "/bin/sh") - def test_user_admin_get_omvs_program_raises_an_exception_when_extract_fails( + def test_user_admin_get_omvs_default_shell_raises_an_exception_when_extract_fails( self, call_racf_mock: Mock, ): @@ -247,13 +249,13 @@ def test_user_admin_get_omvs_program_raises_an_exception_when_extract_fails( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError): - self.user_admin.get_omvs_program("squidwrd") + self.user_admin.get_omvs_default_shell("squidwrd") - def test_user_admin_get_omvs_program_returns_none_when_no_omvs_segment_exists( + def test_user_admin_get_omvs_default_shell_returns_none_when_no_omvs_segment_exists( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML ) - self.assertIsNone(self.user_admin.get_omvs_program("squidwrd")) + self.assertIsNone(self.user_admin.get_omvs_default_shell("squidwrd")) diff --git a/tests/user/test_user_setters.py b/tests/user/test_user_setters.py index cdab89a7..93900ee6 100644 --- a/tests/user/test_user_setters.py +++ b/tests/user/test_user_setters.py @@ -180,13 +180,15 @@ def test_user_admin_build_set_omvs_uid_request(self): # ============================================================================ # OMVS Home # ============================================================================ - def test_user_admin_build_set_omvs_home_request(self): - result = self.user_admin.set_omvs_home("squidwrd", "/u/squidwrd") - self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_HOME_XML) + def test_user_admin_build_set_omvs_home_directory_request(self): + result = self.user_admin.set_omvs_home_directory("squidwrd", "/u/squidwrd") + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_HOME_DIRECTORY_XML + ) # ============================================================================ # OMVS Program # ============================================================================ - def test_user_admin_build_set_omvs_program_request(self): - result = self.user_admin.set_omvs_program("squidwrd", "/bin/sh") - self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_PROGRAM_XML) + def test_user_admin_build_set_omvs_default_shell_request(self): + result = self.user_admin.set_omvs_default_shell("squidwrd", "/bin/sh") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_DEFAULT_SHELL_XML) diff --git a/tests/user/user_log_samples/add_user_additional_secret_added_error.log b/tests/user/user_log_samples/add_user_additional_secret_added_error.log index d8f8dc5a..91446691 100644 --- a/tests/user/user_log_samples/add_user_additional_secret_added_error.log +++ b/tests/user/user_log_samples/add_user_additional_secret_added_error.log @@ -24,11 +24,11 @@ "value": "********", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_additional_secret_added_success.log b/tests/user/user_log_samples/add_user_additional_secret_added_success.log index 2ad712e4..e7cd0ed6 100644 --- a/tests/user/user_log_samples/add_user_additional_secret_added_success.log +++ b/tests/user/user_log_samples/add_user_additional_secret_added_success.log @@ -24,11 +24,11 @@ "value": "********", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_error.log b/tests/user/user_log_samples/add_user_error.log index e5bba4fe..88dc14dd 100644 --- a/tests/user/user_log_samples/add_user_error.log +++ b/tests/user/user_log_samples/add_user_error.log @@ -24,11 +24,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_passphrase_and_password_error.log b/tests/user/user_log_samples/add_user_passphrase_and_password_error.log index c30b9aba..70a2983d 100644 --- a/tests/user/user_log_samples/add_user_passphrase_and_password_error.log +++ b/tests/user/user_log_samples/add_user_passphrase_and_password_error.log @@ -32,11 +32,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_passphrase_and_password_success.log b/tests/user/user_log_samples/add_user_passphrase_and_password_success.log index dd17d227..d3255b80 100644 --- a/tests/user/user_log_samples/add_user_passphrase_and_password_success.log +++ b/tests/user/user_log_samples/add_user_passphrase_and_password_success.log @@ -32,11 +32,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_passphrase_error.log b/tests/user/user_log_samples/add_user_passphrase_error.log index e3b19e12..e983fff7 100644 --- a/tests/user/user_log_samples/add_user_passphrase_error.log +++ b/tests/user/user_log_samples/add_user_passphrase_error.log @@ -28,11 +28,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_passphrase_success.log b/tests/user/user_log_samples/add_user_passphrase_success.log index 426485c2..37796247 100644 --- a/tests/user/user_log_samples/add_user_passphrase_success.log +++ b/tests/user/user_log_samples/add_user_passphrase_success.log @@ -28,11 +28,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_password_error.log b/tests/user/user_log_samples/add_user_password_error.log index 4bf641d2..867e5a4d 100644 --- a/tests/user/user_log_samples/add_user_password_error.log +++ b/tests/user/user_log_samples/add_user_password_error.log @@ -28,11 +28,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_password_success.log b/tests/user/user_log_samples/add_user_password_success.log index ad25b298..2b2565b6 100644 --- a/tests/user/user_log_samples/add_user_password_success.log +++ b/tests/user/user_log_samples/add_user_password_success.log @@ -28,11 +28,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/add_user_success.log b/tests/user/user_log_samples/add_user_success.log index e462fb22..9051c55a 100644 --- a/tests/user/user_log_samples/add_user_success.log +++ b/tests/user/user_log_samples/add_user_success.log @@ -24,11 +24,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/extract_user_base_omvs_success.log b/tests/user/user_log_samples/extract_user_base_omvs_success.log index f7dc260b..feb9169d 100644 --- a/tests/user/user_log_samples/extract_user_base_omvs_success.log +++ b/tests/user/user_log_samples/extract_user_base_omvs_success.log @@ -187,14 +187,14 @@ }, "omvs": { "uid": 2424, - "home": "/u/squidwrd", - "program": "/bin/sh", - "cputimemax": null, - "assizemax": null, - "fileprocmax": null, - "procusermax": null, - "threadsmax": null, - "mmapareamax": null + "homeDirectory": "/u/squidwrd", + "defaultShell": "/bin/sh", + "maxCpuTime": null, + "maxAddressSpaceSize": null, + "maxFilesPerProcess": null, + "maxProcesses": null, + "maxThreads": null, + "maxFileMappingPages": null } } ] diff --git a/tests/user/user_request_samples/user_set_omvs_program_request.xml b/tests/user/user_request_samples/user_set_omvs_default_shell_request.xml similarity index 100% rename from tests/user/user_request_samples/user_set_omvs_program_request.xml rename to tests/user/user_request_samples/user_set_omvs_default_shell_request.xml diff --git a/tests/user/user_request_samples/user_set_omvs_home_request.xml b/tests/user/user_request_samples/user_set_omvs_home_directory_request.xml similarity index 100% rename from tests/user/user_request_samples/user_set_omvs_home_request.xml rename to tests/user/user_request_samples/user_set_omvs_home_directory_request.xml diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json b/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json index 272badfe..578a62a4 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json @@ -50,13 +50,13 @@ }, "omvs": { "uid": 2424, - "home": "/u/clarinet", - "cputimemax": null, - "assizemax": null, - "fileprocmax": null, - "procusermax": null, - "threadsmax": null, - "mmapareamax": null + "homeDirectory": "/u/clarinet", + "maxCpuTime": null, + "maxAddressSpaceSize": null, + "maxFilesPerProcess": null, + "maxProcesses": null, + "maxThreads": null, + "maxFileMappingPages": null } } ] diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_success.json b/tests/user/user_result_samples/extract_user_result_base_omvs_success.json index 64898407..79ceb80d 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_success.json @@ -49,14 +49,14 @@ }, "omvs": { "uid": 2424, - "home": "/u/squidwrd", - "program": "/bin/sh", - "cputimemax": null, - "assizemax": null, - "fileprocmax": null, - "procusermax": null, - "threadsmax": null, - "mmapareamax": null + "homeDirectory": "/u/squidwrd", + "defaultShell": "/bin/sh", + "maxCpuTime": null, + "maxAddressSpaceSize": null, + "maxFilesPerProcess": null, + "maxProcesses": null, + "maxThreads": null, + "maxFileMappingPages": null } } ] From b9c0bb7c54039beddd912103bc8e156ee46e481e Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Sat, 21 Oct 2023 11:52:27 -0400 Subject: [PATCH 31/72] Update user traits and add new date converter. Signed-off-by: Leonard Carcaramo --- pyracf/common/security_admin.py | 11 ++++++++--- pyracf/user/user_admin.py | 10 ++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 4b1282d0..a155af4a 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -703,25 +703,30 @@ def _cast_from_str(self, value: str) -> Union[None, bool, int, float, str]: def __cast_num(self, value: str) -> Union[int, float, str]: value = value.strip() - if "." in value: + if "." in value or "," in value: try: # Convert Julian timestamps to standard date format. t = "-" if platform.system() == "Windows": # Allows unit tests to be run on Windows. t = "#" + build_standard_date = f"%{t}m/%{t}d/%Y" + build_standard_date_with_time = f"%{t}m/%{t}d/%Y %{t}I:%M %p" julian_regex = r"\d\d.\d\d\d$" julian_with_time_regex = r"\d\d.\d\d\d/\d\d:\d\d:\d\d$" + expanded_non_julian_date_regex = r"[a-z]* (\d\d|\d), \d\d\d\d$" if re.match(julian_regex, value): read_julian_date = "%y.%j" - build_standard_date = f"%{t}m/%{t}d/%Y" date = datetime.strptime(value, read_julian_date) return date.strftime(build_standard_date) elif re.match(julian_with_time_regex, value): read_julian_date_with_time = "%y.%j/%H:%M:%S" - build_standard_date_with_time = f"%{t}m/%{t}d/%Y %{t}I:%M %p" date = datetime.strptime(value, read_julian_date_with_time) return date.strftime(build_standard_date_with_time) + elif re.match(expanded_non_julian_date_regex, value): + read_expanded_non_julian_date = "%B %d, %Y" + date = datetime.strptime(value, read_expanded_non_julian_date) + return date.strftime(build_standard_date) except ValueError: return None try: diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 3b5f6460..6b17e618 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -38,8 +38,8 @@ def __init__( "base:password": "racf:password", "base:passphrase": "racf:phrase", "base:restrict_global_access_checking": "racf:rest", - "base:resume": "resumedate", - "base:revoke": "revokedate", + "base:resume_date": "resumedate", + "base:revoke_date": "revokedate", "base:audit_responsibility": "racf:roaudit", "base:security_label": "seclabel", "base:security_level": "racf:seclevel", @@ -106,7 +106,7 @@ def __init__( "omvs:max_cpu_time": "cputime", "omvs:max_files_per_process": "filemax", "omvs:home_directory": "home", - "omvs:max_nonshared_memory": "memlim", + "omvs:max_non_shared_memory": "memlim", "omvs:max_file_mapping_pages": "mmaparea", "omvs:max_processes": "procmax", "omvs:default_shell": "pgm", @@ -184,12 +184,14 @@ def __init__( "procusermax": "maxProcesses", "threadsmax": "maxThreads", "mmapareamax": "maxFileMappingPages", + "memlimit": "maxNonSharedMemory", + "shmemmax": "maxSharedMemory", }, "tso": { "acctnum": "accountNumber", "jobclass": "jobClass", "msgclass": "messageClass", - "proc": "procedure", + "proc": "logonProcedure", "size": "regionSize", "maxsize": "maxRegionSize", "sysoutclass": "sysoutClass", From e2aca1a245a3ebfa4bc7652bd5213d52f003a304 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Sat, 21 Oct 2023 15:02:33 -0400 Subject: [PATCH 32/72] Add Segment-Trait validation Throw InvalidSegmentTraitError when there is an invalid segment trait combination. Signed-off-by: Elijah Swift --- pyracf/common/invalid_segment_trait_error.py | 18 ++++++++++++++++++ pyracf/common/security_admin.py | 15 ++++++++++++++- tests/user/test_user_constants.py | 6 +++++- tests/user/test_user_request_builder.py | 3 ++- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 pyracf/common/invalid_segment_trait_error.py diff --git a/pyracf/common/invalid_segment_trait_error.py b/pyracf/common/invalid_segment_trait_error.py new file mode 100644 index 00000000..be9d92ba --- /dev/null +++ b/pyracf/common/invalid_segment_trait_error.py @@ -0,0 +1,18 @@ +"""Exception to use when the user passes invalid segment-trait(s) in the traits dictionary.""" + + +class InvalidSegmentTraitError(Exception): + """ + Raised when a user passes an invalid segment-trait combination in the traits dictionary. + """ + + def __init__(self, invalid_traits: list) -> None: + self.message = "Building of Security Request failed.\n\n" + for trait in invalid_traits: + self.message += ( + "Could not find " + + f"'{trait}' in valid segment traits for the requested operation.\n" + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index c9540769..020e3f17 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -5,6 +5,7 @@ from datetime import datetime from typing import Any, List, Tuple, Union +from .invalid_segment_trait_error import InvalidSegmentTraitError from .irrsmo00 import IRRSMO00 from .logger import Logger from .security_request import SecurityRequest @@ -266,9 +267,21 @@ def _build_bool_segment_dictionaries(self, segments: dict) -> None: def _build_segment_dictionaries(self, traits: dict) -> None: """Build segemnt dictionaries for each segment.""" + invalid_traits = [] for trait in traits: + trait_valid = False for segment in self._valid_segment_traits: - self.__validate_and_add_trait(trait, segment, traits[trait]) + trait_valid = self.__validate_and_add_trait( + trait, segment, traits[trait] + ) + if trait_valid: + break + if not trait_valid: + invalid_traits.append(trait) + + if invalid_traits: + raise InvalidSegmentTraitError(invalid_traits) + # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 99c53d1c..55641af3 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -229,12 +229,16 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter User Traits -TEST_ALTER_USER_CSDATA_REQUEST_TRAITS = { +TEST_ALTER_USER_CSDATA_AND_OMVS_REQUEST_TRAITS = { "base:special": False, "omvs:home": "/u/clarinet", "omvs:program": False, "csdata:tstcsfld": "testval", } +TEST_ALTER_USER_CSDATA_REQUEST_TRAITS = { + "base:special": False, + "csdata:tstcsfld": "testval", +} # Valid Segment Traits Updates TEST_USER_REPLACE_SEGMENT_TRAITS = { diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 83381564..ba997e4e 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -104,7 +104,8 @@ def test_user_admin_build_alter_request_update_existing_segment_traits(self): update_existing_segment_traits=TestUserConstants.TEST_USER_ADDITIONAL_SEGMENT_TRAITS, ) result = user_admin.alter( - "squidwrd", traits=TestUserConstants.TEST_ALTER_USER_CSDATA_REQUEST_TRAITS + "squidwrd", + traits=TestUserConstants.TEST_ALTER_USER_CSDATA_AND_OMVS_REQUEST_TRAITS, ) self.assertEqual( result, From 8f3bd5e4637da1670994cc4a3b9ee6348c1dca0b Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Sat, 21 Oct 2023 15:32:20 -0400 Subject: [PATCH 33/72] Add base, omvs, and tso, add user test, and add beta version getters and setters. Signed-off-by: Leonard Carcaramo --- pyracf/common/security_admin.py | 13 +- pyracf/user/user_admin.py | 388 +++++++++++++++++- tests/user/test_user_constants.py | 38 ++ tests/user/test_user_request_builder.py | 11 + tests/user/test_user_result_parser.py | 12 + ...er_request_base_omvs_tso_revoke_resume.xml | 36 ++ ...er_result_base_omvs_tso_revoke_resume.json | 81 ++++ ...ser_result_base_omvs_tso_revoke_resume.xml | 59 +++ 8 files changed, 626 insertions(+), 12 deletions(-) create mode 100644 tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml create mode 100644 tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json create mode 100644 tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index a155af4a..c93bf20a 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -309,14 +309,21 @@ def _get_profile( ] def _get_field( - self, profile: Union[dict, bytes], segment: str, field: str + self, + profile: Union[dict, bytes], + segment: str, + field: str, + string: bool = False, ) -> Union[bytes, Any, None]: """Extract the value of a field from a segment in a profile.""" if self.__generate_requests_only: # Allows this function to work with "self.__generate_requests_only" mode. return profile try: - return profile[segment][field] + field = profile[segment][field] + if string and field is not None: + return str(field) + return field except KeyError: return None @@ -611,7 +618,7 @@ def __add_key_value_pairs_to_segment( if current_key not in segment: segment[current_key] = [] values = [ - self._cast_from_str(value) + str(self._cast_from_str(value)) for value in value.split() if value != "NONE" ] diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 6b17e618..9302885c 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -335,6 +335,58 @@ def delete_all_class_authorizations(self, userid: str) -> Union[dict, bool, byte return False return self.remove_class_authorizations(userid, current_class_authorizations) + # ============================================================================ + # Revoke Date + # ============================================================================ + def get_revoke_date(self, userid: str) -> Union[str, None, bytes]: + """Get a user's revoke date.""" + profile = self.extract(userid, profile_only=True) + return self._get_field(profile, "base", "revokeDate", string=True) + + def set_revoke_date(self, userid: str, revoke_date: str) -> Union[dict, bytes]: + """Set a user's revoke date.""" + result = self.alter(userid, traits={"base:revoke_date": revoke_date}) + return self._to_steps(result) + + # ============================================================================ + # Resume Date + # ============================================================================ + def get_resume_date(self, userid: str) -> Union[str, None, bytes]: + """Get a user's resume date.""" + profile = self.extract(userid, profile_only=True) + return self._get_field(profile, "base", "resumeDate", string=True) + + def set_resume_date(self, userid: str, resume_date: str) -> Union[dict, bytes]: + """Set a user's resume date.""" + result = self.alter(userid, traits={"base:resume_date": resume_date}) + return self._to_steps(result) + + # ============================================================================ + # Owner + # ============================================================================ + def get_owner(self, userid: str) -> Union[str, bytes]: + """Get a user's owner.""" + profile = self.extract(userid, profile_only=True) + return self._get_field(profile, "base", "owner", string=True) + + def set_owner(self, userid: str, owner: str) -> Union[dict, bytes]: + """Set a user's owner.""" + result = self.alter(userid, traits={"base:owner": owner}) + return self._to_steps(result) + + # ============================================================================ + # Name + # ============================================================================ + def get_name(self, userid: str) -> Union[str, bytes]: + """Get a user's name.""" + profile = self.extract(userid, profile_only=True) + return self._get_field(profile, "base", "name", string=True) + + def set_name(self, userid: str, name: Union[str, bool]) -> Union[dict, bytes]: + """Set a user's name.""" + result = self.alter(userid, traits={"base:name": name}) + return self._to_steps(result) + # ============================================================================ # OMVS UID # ============================================================================ @@ -343,45 +395,363 @@ def get_omvs_uid(self, userid: str) -> Union[int, None, bytes]: profile = self.extract(userid, segments={"omvs": True}, profile_only=True) return self._get_field(profile, "omvs", "uid") - def set_omvs_uid(self, userid: str, uid: int) -> Union[dict, bytes]: + def set_omvs_uid(self, userid: str, uid: Union[int, bool]) -> Union[dict, bytes]: """Set a user's OMVS UID.""" result = self.alter(userid, traits={"omvs:uid": uid}) return self._to_steps(result) # ============================================================================ - # OMVS Home + # OMVS Max Address Space Size + # ============================================================================ + def get_omvs_max_address_space_size(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max address space size.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxAddressSpaceSize") + + def set_omvs_max_address_space_size( + self, + userid: str, + max_address_space_size: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max address space size.""" + result = self.alter( + userid, traits={"omvs:max_address_space_size": max_address_space_size} + ) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max CPU Time + # ============================================================================ + def get_omvs_max_cpu_time(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max cpu time.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxCpuTime") + + def set_omvs_max_cpu_time( + self, + userid: str, + max_cpu_time: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max cpu time.""" + result = self.alter(userid, traits={"omvs:max_cpu_time": max_cpu_time}) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max Files Per Process + # ============================================================================ + def get_omvs_max_files_per_process(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max files per process.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxFilesPerProcess") + + def set_omvs_max_files_per_process( + self, + userid: str, + max_files_per_process: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max files per process.""" + result = self.alter( + userid, traits={"omvs:max_files_per_process": max_files_per_process} + ) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max Non-Shared Memory + # ============================================================================ + def get_omvs_max_non_shared_memory(self, userid: str) -> Union[str, None, bytes]: + """Get a user's OMVS max non-shared memory.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxNonSharedMemory", string=True) + + def set_omvs_max_non_shared_memory( + self, + userid: str, + max_non_shared_memory: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max non-shared memory.""" + result = self.alter( + userid, traits={"omvs:max_non_shared_memory": max_non_shared_memory} + ) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max File Mapping Pages + # ============================================================================ + def get_omvs_max_file_mapping_pages(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max file mapping pages.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxFileMappingPages") + + def set_omvs_max_file_mapping_pages( + self, + userid: str, + max_file_mapping_pages: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max file mapping pages.""" + result = self.alter( + userid, traits={"omvs:max_file_mapping_pages": max_file_mapping_pages} + ) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max Processes + # ============================================================================ + def get_omvs_max_processes(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max processes.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxProcesses") + + def set_omvs_max_processes( + self, + userid: str, + max_processes: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max processes.""" + result = self.alter(userid, traits={"omvs:max_processes": max_processes}) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max Shared Memory + # ============================================================================ + def get_omvs_max_shared_memory(self, userid: str) -> Union[str, None, bytes]: + """Get a user's OMVS max shared memory.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxSharedMemory", string=True) + + def set_omvs_max_shared_memory( + self, + userid: str, + max_shared_memory: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max shared memory.""" + result = self.alter( + userid, traits={"omvs:max_shared_memory": max_shared_memory} + ) + return self._to_steps(result) + + # ============================================================================ + # OMVS Max Threads + # ============================================================================ + def get_omvs_max_threads(self, userid: str) -> Union[int, None, bytes]: + """Get a user's OMVS max threads.""" + profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + return self._get_field(profile, "omvs", "maxThreads") + + def set_omvs_max_threads( + self, + userid: str, + max_threads: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS max threads.""" + result = self.alter(userid, traits={"omvs:max_threads": max_threads}) + return self._to_steps(result) + + # ============================================================================ + # OMVS Home Directory # ============================================================================ def get_omvs_home_directory(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS home directory.""" profile = self.extract(userid, segments={"omvs": True}, profile_only=True) - return self._get_field(profile, "omvs", "homeDirectory") + return self._get_field(profile, "omvs", "homeDirectory", string=True) def set_omvs_home_directory( self, userid: str, - home_directory: str, + home_directory: Union[str, bool], ) -> Union[dict, bytes]: """Set a user's OMVS home directory.""" result = self.alter(userid, traits={"omvs:home_directory": home_directory}) return self._to_steps(result) # ============================================================================ - # OMVS Program + # OMVS Default Shell # ============================================================================ def get_omvs_default_shell(self, userid: str) -> Union[str, None, bytes]: - """Get a user's OMVS program.""" + """Get a user's OMVS default shell.""" profile = self.extract(userid, segments={"omvs": True}, profile_only=True) - return self._get_field(profile, "omvs", "defaultShell") + return self._get_field(profile, "omvs", "defaultShell", string=True) def set_omvs_default_shell( self, userid: str, - program: str, + program: Union[str, bool], ) -> Union[dict, bytes]: - """Set a user's OMVS program.""" + """Set a user's OMVS default shell.""" result = self.alter(userid, traits={"omvs:default_shell": program}) return self._to_steps(result) + # ============================================================================ + # TSO Account Number + # ============================================================================ + def get_tso_account_number(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO account number.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "accountNumber", string=True) + + def set_tso_account_number( + self, + userid: str, + account_number: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO account number.""" + result = self.alter(userid, traits={"tso:account_number": account_number}) + return self._to_steps(result) + + # ============================================================================ + # TSO Logon Command + # ============================================================================ + def get_tso_logon_command(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO logon command.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "logonCommand", string=True) + + def set_tso_logon_command( + self, + userid: str, + logon_command: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO logon command.""" + result = self.alter(userid, traits={"tso:logon_command": logon_command}) + return self._to_steps(result) + + # ============================================================================ + # TSO Hold Class + # ============================================================================ + def get_tso_hold_class(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO hold class.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "holdClass", string=True) + + def set_tso_hold_class( + self, + userid: str, + hold_class: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO hold class.""" + result = self.alter(userid, traits={"tso:hold_class": hold_class}) + return self._to_steps(result) + + # ============================================================================ + # TSO Max Region Size + # ============================================================================ + def get_tso_max_region_size(self, userid: str) -> Union[int, None, bytes]: + """Get a user's TSO max region size.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "maxRegionSize") + + def set_tso_max_region_size( + self, + userid: str, + max_region_size: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO max region size.""" + result = self.alter(userid, traits={"tso:max_region_size": max_region_size}) + return self._to_steps(result) + + # ============================================================================ + # TSO Message Class + # ============================================================================ + def get_tso_message_class(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO message class.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "messageClass", string=True) + + def set_tso_message_class( + self, + userid: str, + message_class: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO message class.""" + result = self.alter(userid, traits={"tso:message_class": message_class}) + return self._to_steps(result) + + # ============================================================================ + # TSO Logon Procedure + # ============================================================================ + def get_tso_logon_procedure(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO logon procedure.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "logonProcedure", string=True) + + def set_tso_logon_procedure( + self, + userid: str, + logon_procedure: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO logon procedure.""" + result = self.alter(userid, traits={"tso:logon_procedure": logon_procedure}) + return self._to_steps(result) + + # ============================================================================ + # TSO Region Size + # ============================================================================ + def get_tso_region_size(self, userid: str) -> Union[int, None, bytes]: + """Get a user's TSO region size.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "regionSize") + + def set_tso_region_size( + self, + userid: str, + region_size: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO region size.""" + result = self.alter(userid, traits={"tso:region_size": region_size}) + return self._to_steps(result) + + # ============================================================================ + # TSO Sysout Class + # ============================================================================ + def get_tso_sysout_class(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO sysout class.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "sysoutClass", string=True) + + def set_tso_sysout_class( + self, + userid: str, + sysout_class: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO sysout class.""" + result = self.alter(userid, traits={"tso:sysout_class": sysout_class}) + return self._to_steps(result) + + # ============================================================================ + # TSO User Data + # ============================================================================ + def get_tso_user_data(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO user data.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "userData", string=True) + + def set_tso_user_data( + self, + userid: str, + user_data: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO user data.""" + result = self.alter(userid, traits={"tso:user_data": user_data}) + return self._to_steps(result) + + # ============================================================================ + # TSO Data Set Allocation Unit + # ============================================================================ + def get_tso_data_set_allocation_unit(self, userid: str) -> Union[str, None, bytes]: + """Get a user's TSO data set allocation unit.""" + profile = self.extract(userid, segments={"tso": True}, profile_only=True) + return self._get_field(profile, "tso", "dataSetAllocationUnit", string=True) + + def set_tso_data_set_allocation_unit( + self, + userid: str, + data_set_allocation_unit: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO data set allocation unit.""" + result = self.alter( + userid, traits={"tso:data_set_allocation_unit": data_set_allocation_unit} + ) + return self._to_steps(result) + # ============================================================================ # Base Functions # ============================================================================ diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 75a12aa1..3f534166 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -88,6 +88,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample( "extract_user_result_with_command_audit_trail.xml" ) +TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML = get_sample( + "extract_user_result_base_omvs_tso_revoke_resume.xml" +) +TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY = get_sample( + "extract_user_result_base_omvs_tso_revoke_resume.json" +) # Delete User TEST_DELETE_USER_RESULT_SUCCESS_XML = get_sample("delete_user_result_success.xml") @@ -103,6 +109,9 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Add User TEST_ADD_USER_REQUEST_XML = get_sample("add_user_request.xml") +TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_XML = get_sample( + "add_user_request_base_omvs_tso_revoke_resume.xml" +) TEST_ADD_USER_REQUEST_PASSWORD_XML = get_sample("add_user_request_password.xml") TEST_ADD_USER_REQUEST_PASSPHRASE_XML = get_sample("add_user_request_passphrase.xml") TEST_ADD_USER_REQUEST_PASSPHRASE_AND_PASSWORD_XML = get_sample( @@ -117,6 +126,35 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "omvs:home_directory": "/u/squidwrd", "omvs:default_shell": "/bin/sh", } +TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_TRAITS = { + "base:name": "Squidward", + "base:password": "PASSWORD", + "base:owner": "LEONARD", + "base:revoke_date": "10/22/23", + "base:resume_date": "11/2/23", + "omvs:max_address_space_size": 10485760, + "omvs:max_cpu_time": 1500, + "omvs:max_files_per_process": 50, + "omvs:max_non_shared_memory": "4g", + "omvs:max_file_mapping_pages": 350, + "omvs:max_processes": 128, + "omvs:shared": True, + "omvs:max_shared_memory": "2g", + "omvs:max_therads": 48, + "omvs:uid": 1919, + "omvs:home_directory": "/u/squidward", + "omvs:default_shell": "/bin/sh", + "tso:account_number": "D999", + "tso:logon_command": "ISPF", + "tso:hold_class": "A", + "tso:max_region_size": 2048, + "tso:message_class": "O", + "tso:logon_procedure": "PROC", + "tso:region_size": 1024, + "tso:sysout_class": "O", + "tso:user_data": "ABCD", + "tso:data_set_allocation_unit": "SYSDA", +} TEST_ADD_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ADD_USER_REQUEST_TRAITS) TEST_ADD_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF" TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE = dict(TEST_ADD_USER_REQUEST_TRAITS) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 83381564..a3e8d34a 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -29,6 +29,17 @@ def test_user_admin_build_add_user_request(self): ) self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_XML) + def test_user_admin_build_add_user_base_omvs_tso_revoke_resume_request(self): + result = self.user_admin.add( + "squidwrd", + traits=TestUserConstants.TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_TRAITS, + ) + print(result) + self.assertEqual( + result, + TestUserConstants.TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_XML, + ) + def test_user_admin_build_alter_user_request(self): result = self.user_admin.alter( "squidwrd", traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index c3b0ef8e..99501a82 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -140,6 +140,18 @@ def test_user_admin_can_parse_extract_user_and_ignore_command_audit_trail_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) + def test_user_admin_can_parse_extract_user_base_omvs_tso_revoke_resume_success_xml( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual( + self.user_admin.extract("squidwrd", segments={"omvs": True, "tso": True}), + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY, + ) + # ============================================================================ # Password and Password Phrase Redaction # ============================================================================ diff --git a/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml new file mode 100644 index 00000000..a69e7455 --- /dev/null +++ b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml @@ -0,0 +1,36 @@ + + + + Squidward + ******** + LEONARD + 10/22/23 + 11/2/23 + + + 10485760 + 1500 + 50 + 4g + 350 + 128 + + 2g + 1919 + /u/squidward + /bin/sh + + + D999 + ISPF + A + 2048 + O + PROC + 1024 + O + ABCD + SYSDA + + + \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json new file mode 100644 index 00000000..817d728d --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json @@ -0,0 +1,81 @@ +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD OMVS TSO ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidwrd", + "owner": "leonard", + "created": "10/21/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": "10/22/2023", + "resumeDate": "11/2/2023", + "lastAccess": "10/21/2023 12:20 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "10/21/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + }, + "omvs": { + "uid": 1919, + "homeDirectory": "/u/squidward", + "defaultShell": "/bin/sh", + "maxCpuTime": 1500, + "maxAddressSpaceSize": 10485760, + "maxFilesPerProcess": 50, + "maxProcesses": 128, + "maxThreads": null, + "maxFileMappingPages": 350, + "maxNonSharedMemory": "4g", + "maxSharedMemory": "2g" + }, + "tso": { + "accountNumber": "d999", + "holdclass": "a", + "messageClass": "o", + "logonProcedure": "proc", + "regionSize": 1024, + "maxRegionSize": 2048, + "sysoutClass": "o", + "dataSetAllocationUnit": "sysda", + "userData": "abcd", + "logonCommand": "ispf" + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml new file mode 100644 index 00000000..f38c2573 --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml @@ -0,0 +1,59 @@ + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD OMVS TSO + USER=SQUIDWRD NAME=SQUIDWRD OWNER=LEONARD CREATED=23.294 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=OCTOBER 22, 2023 RESUME DATE=NOVEMBER 2, 2023 + LAST-ACCESS=23.294/12:20:06 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.294 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + OMVS INFORMATION + ---------------- + UID= 0000001919 + HOME= /u/squidward + PROGRAM= /bin/sh + CPUTIMEMAX= 0000001500 + ASSIZEMAX= 0010485760 + FILEPROCMAX= 00000050 + PROCUSERMAX= 00000128 + THREADSMAX= NONE + MMAPAREAMAX= 00000350 + MEMLIMIT= 4G + SHMEMMAX= 2G + + TSO INFORMATION + --------------- + ACCTNUM= D999 + HOLDCLASS= A + MSGCLASS= O + PROC= PROC + SIZE= 00001024 + MAXSIZE= 00002048 + SYSOUTCLASS= O + UNIT= SYSDA + USERDATA= ABCD + COMMAND= ISPF + + + 0 + 0 + \ No newline at end of file From 35e51766578870222f4f339873ff6837db632861 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Sat, 21 Oct 2023 17:15:11 -0400 Subject: [PATCH 34/72] Add Unit Testing for AlterOperationError Unit test to confirm that Alters for Group, Resource, User and Data Set Admin all throw AlterOperationError when failing in the EXTRACT step. Signed-off-by: Elijah Swift --- pyracf/__init__.py | 2 ++ tests/data_set/test_data_set_result_parser.py | 24 +++++++++++++++++- tests/group/test_group_result_parser.py | 23 ++++++++++++++++- tests/resource/test_resource_result_parser.py | 25 ++++++++++++++++++- tests/user/test_user_result_parser.py | 23 ++++++++++++++++- 5 files changed, 93 insertions(+), 4 deletions(-) diff --git a/pyracf/__init__.py b/pyracf/__init__.py index 70dd53f6..379dd12b 100644 --- a/pyracf/__init__.py +++ b/pyracf/__init__.py @@ -1,5 +1,7 @@ """Make security admin subclasses available from package root.""" from .access.access_admin import AccessAdmin +from .common.alter_operation_error import AlterOperationError +from .common.invalid_segment_trait_error import InvalidSegmentTraitError from .common.security_request_error import SecurityRequestError from .connection.connection_admin import ConnectionAdmin from .data_set.data_set_admin import DataSetAdmin diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 672f476a..1dae2aa3 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -6,7 +6,7 @@ import __init__ import tests.data_set.test_data_set_constants as TestDataSetConstants -from pyracf import DataSetAdmin, SecurityRequestError +from pyracf import AlterOperationError, DataSetAdmin, SecurityRequestError from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -74,6 +74,28 @@ def test_data_set_admin_can_parse_alter_data_set_success_xml( TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_DICTIONARY, ) + def test_data_set_admin_thows_error_on_alter_new_data_set_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "ESWIFT.TEST.T1136242.P3020470" + class_name = "DATASET" + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.data_set_admin.alter( + profile_name, + traits=TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a {class_name} profile.", + ) + # Error in environment, ESWIFT.TEST.T1136242.P3020470 data set does not exist def test_data_set_admin_can_parse_alter_data_set_error_xml( self, diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 4f906c85..650ed110 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -6,7 +6,7 @@ import __init__ import tests.group.test_group_constants as TestGroupConstants -from pyracf import GroupAdmin, SecurityRequestError +from pyracf import AlterOperationError, GroupAdmin, SecurityRequestError from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -69,6 +69,27 @@ def test_group_admin_can_parse_alter_group_success_xml( TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_DICTIONARY, ) + def test_group_admin_throws_error_on_alter_new_group( + self, + call_racf_mock: Mock, + ): + group_name = "TESTGRP0" + admin_name = "GROUP" + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.group_admin.alter( + group_name, traits=TestGroupConstants.TEST_ALTER_GROUP_REQUEST_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{group_name}' does not exist as a {admin_name} profile.", + ) + # Error: invalid gid "3000000000" def test_group_admin_can_parse_alter_group_error_xml( self, diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index d60700d6..7b5bc9b0 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -6,7 +6,7 @@ import __init__ import tests.resource.test_resource_constants as TestResourceConstants -from pyracf import ResourceAdmin, SecurityRequestError +from pyracf import AlterOperationError, ResourceAdmin, SecurityRequestError from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -69,6 +69,29 @@ def test_resource_admin_can_parse_alter_resource_success_xml( TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_DICTIONARY, ) + def test_resource_admin_throws_error_on_alter_new_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "TESTING" + class_name = "ELIJTEST" + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_ERROR_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.resource_admin.alter( + profile_name, + class_name, + traits=TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a profile in the {class_name} class.", + ) + # Error: Invalid Universal Access ALL def test_resource_admin_can_parse_alter_resource_error_xml( self, diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 59d9628f..64c9f83e 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -6,7 +6,7 @@ import __init__ import tests.user.test_user_constants as TestUserConstants -from pyracf import SecurityRequestError, UserAdmin +from pyracf import AlterOperationError, SecurityRequestError, UserAdmin from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -72,6 +72,27 @@ def test_user_admin_can_parse_alter_user_success_xml( TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_DICTIONARY, ) + def test_user_admin_throws_error_on_alter_new_user( + self, + call_racf_mock: Mock, + ): + profile_name = "squidwrd" + admin_name = "USER" + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.user_admin.alter( + profile_name, traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a {admin_name} profile.", + ) + # Error: invalid parameter "name" def test_user_admin_can_parse_alter_user_error_xml( self, From ab83282ec8a143e5b1048118a625da4229e6183f Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Sun, 22 Oct 2023 13:00:47 -0400 Subject: [PATCH 35/72] Add testing new user getters and setters and fix a couple bugs. Signed-off-by: Leonard Carcaramo --- pyracf/common/logger.py | 9 + pyracf/common/security_admin.py | 17 +- pyracf/connection/connection_admin.py | 3 +- pyracf/resource/resource_admin.py | 19 +- pyracf/user/user_admin.py | 26 +- ...tract_group_result_base_only_success.json} | 0 ...xtract_group_result_base_only_success.xml} | 0 tests/group/test_group_constants.py | 8 +- tests/group/test_group_getters.py | 16 +- tests/group/test_group_result_parser.py | 6 +- tests/user/test_user_constants.py | 145 +++- tests/user/test_user_getters.py | 818 +++++++++++++++++- tests/user/test_user_result_parser.py | 8 +- tests/user/test_user_setters.py | 325 ++++++- ...er_request_base_omvs_tso_revoke_resume.xml | 5 +- .../user_set_name_delete_request.xml | 8 + .../user_set_name_request.xml | 8 + ..._set_omvs_default_shell_delete_request.xml | 7 + ...set_omvs_home_directory_delete_request.xml | 7 + ..._max_address_space_size_delete_request.xml | 7 + ...et_omvs_max_address_space_size_request.xml | 7 + ...r_set_omvs_max_cpu_time_delete_request.xml | 7 + .../user_set_omvs_max_cpu_time_request.xml | 7 + ..._max_file_mapping_pages_delete_request.xml | 7 + ...et_omvs_max_file_mapping_pages_request.xml | 7 + ...s_max_files_per_process_delete_request.xml | 7 + ...set_omvs_max_files_per_process_request.xml | 7 + ...s_max_non_shared_memory_delete_request.xml | 7 + ...set_omvs_max_non_shared_memory_request.xml | 7 + ..._set_omvs_max_processes_delete_request.xml | 8 + .../user_set_omvs_max_processes_request.xml | 8 + ..._omvs_max_shared_memory_delete_request.xml | 7 + ...ser_set_omvs_max_shared_memory_request.xml | 7 + ...er_set_omvs_max_threads_delete_request.xml | 7 + .../user_set_omvs_max_threads_request.xml | 7 + .../user_set_omvs_uid_delete_request.xml | 7 + .../user_set_owner_request.xml | 7 + .../user_set_passphrase_delete_request.xml | 7 + .../user_set_password_delete_request.xml | 7 + .../user_set_resume_date_delete_request.xml | 7 + .../user_set_resume_date_request.xml | 7 + .../user_set_revoke_date_delete_request.xml | 8 + .../user_set_revoke_date_request.xml | 8 + ..._set_tso_account_number_delete_request.xml | 8 + .../user_set_tso_account_number_request.xml | 8 + ...ata_set_allocation_unit_delete_request.xml | 7 + ...t_tso_data_set_allocation_unit_request.xml | 7 + ...tso_default_region_size_delete_request.xml | 7 + ...er_set_tso_default_region_size_request.xml | 7 + ...user_set_tso_hold_class_delete_request.xml | 8 + .../user_set_tso_hold_class_request.xml | 8 + ...r_set_tso_logon_command_delete_request.xml | 7 + .../user_set_tso_logon_command_request.xml | 7 + ...set_tso_logon_procedure_delete_request.xml | 7 + .../user_set_tso_logon_procedure_request.xml | 7 + ...set_tso_max_region_size_delete_request.xml | 8 + .../user_set_tso_max_region_size_request.xml | 8 + ...r_set_tso_message_class_delete_request.xml | 7 + .../user_set_tso_message_class_request.xml | 7 + ...er_set_tso_sysout_class_delete_request.xml | 7 + .../user_set_tso_sysout_class_request.xml | 7 + .../user_set_tso_user_data_delete_request.xml | 8 + .../user_set_tso_user_data_request.xml | 8 + ...er_result_base_omvs_tso_revoke_resume.json | 12 +- ...ser_result_base_omvs_tso_revoke_resume.xml | 8 +- ...xtract_user_result_base_only_success.json} | 0 ...extract_user_result_base_only_success.xml} | 0 67 files changed, 1689 insertions(+), 86 deletions(-) rename tests/group/group_result_samples/{extract_group_result_base_only_no_omvs_success.json => extract_group_result_base_only_success.json} (100%) rename tests/group/group_result_samples/{extract_group_result_base_only_no_omvs_success.xml => extract_group_result_base_only_success.xml} (100%) create mode 100644 tests/user/user_request_samples/user_set_name_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_name_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_default_shell_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_home_directory_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_address_space_size_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_address_space_size_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_cpu_time_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_cpu_time_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_files_per_process_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_files_per_process_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_processes_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_processes_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_shared_memory_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_shared_memory_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_threads_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_max_threads_request.xml create mode 100644 tests/user/user_request_samples/user_set_omvs_uid_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_owner_request.xml create mode 100644 tests/user/user_request_samples/user_set_passphrase_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_password_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_resume_date_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_resume_date_request.xml create mode 100644 tests/user/user_request_samples/user_set_revoke_date_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_revoke_date_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_account_number_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_account_number_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_default_region_size_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_default_region_size_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_hold_class_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_hold_class_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_logon_command_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_logon_command_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_logon_procedure_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_logon_procedure_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_max_region_size_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_max_region_size_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_message_class_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_message_class_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_sysout_class_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_sysout_class_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_user_data_delete_request.xml create mode 100644 tests/user/user_request_samples/user_set_tso_user_data_request.xml rename tests/user/user_result_samples/{extract_user_result_base_only_no_omvs_success.json => extract_user_result_base_only_success.json} (100%) rename tests/user/user_result_samples/{extract_user_result_base_only_no_omvs_success.xml => extract_user_result_base_only_success.xml} (100%) diff --git a/pyracf/common/logger.py b/pyracf/common/logger.py index 07a491ae..805a6222 100644 --- a/pyracf/common/logger.py +++ b/pyracf/common/logger.py @@ -145,6 +145,15 @@ def redact_request_xml( match = re.search(rf"\<{xml_key}+[^>]*\>", xml_string) if not match: continue + # Delete operation has no end tag and and redaction should not be attempted. + # + # Redact this: + # secret + # + # Don't try to redact this: + # + if f"" not in xml_string: + continue xml_string = self.__redact_string(xml_string, match.end(), f" Union[list, str]: return out - def _cast_from_str(self, value: str) -> Union[None, bool, int, float, str]: + def _cast_from_str( + self, + value: str, + case_sensitive: bool = False, + ) -> Union[None, bool, int, float, str]: """Cast null values floats and integers.""" - value = value.lower() + if not case_sensitive: + value = value.lower() if value in ("n/a", "none", "none specified", "no", "None"): return None if value in ( diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index 27ddbb58..29596332 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -28,8 +28,7 @@ def __init__( "base:owner": "racf:owner", "base:resume": "racf:resume", "base:revoke": "racf:revoke", - "base:revokefl": "racf:revokefl", # What is the point of this. - "base:special": "racf:special", # Just need 'base:revoke', no? + "base:special": "racf:special", "base:universal_access": "racf:uacc", } } diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 8a975f7b..c2f29ec2 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -38,10 +38,9 @@ def __init__( "base:global_audit_read": "racf:gaudread", "base:global_audit_update": "racf:gaudupdt", "base:level": "racf:level", - "base:member_resources": "racf:member", + "base:member": "racf:member", "base:notify_userid": "racf:notify", "base:owner": "racf:owner", - "base:profile": "racf:profile", # Not documented... "base:security_label": "racf:seclabel", "base:security_level": "racf:seclevel", "base:single_data_set_tape_volume": "racf:singldsn", @@ -54,17 +53,17 @@ def __init__( "base:terminal_access_allowed_time": "racf:whentime", }, "cdtinfo": { - "cdtinfo:mixed_case_allowed": "case", + "cdtinfo:case_allowed": "case", "cdtinfo:default_racroute_return_code": "defaultrc", "cdtinfo:valid_first_characters": "first", "cdtinfo:generic": "generic", - "cdtinfo:setropts_genlist_allowed": "genlist", + "cdtinfo:genlist": "genlist", "cdtinfo:grouping_class_name": "grouping", "cdtinfo:key_qualifiers": "keyqual", "cdtinfo:manditory_access_control_processing": "macprocessing", "cdtinfo:max_length": "maxlenx", "cdtinfo:max_length_racroute": "maxlength", - "cdtinfo:member_class": "member", + "cdtinfo:member_class_name": "member", "cdtinfo:operations": "operations", "cdtinfo:valid_other_characters": "other", "cdtinfo:posit_number": "posit", @@ -75,7 +74,7 @@ def __init__( "cdtinfo:default_universal_access": "defaultuacc", }, "cfdef": { - "cfdef:cfdtype": "type", + "cfdef:custom_field_data_type": "type", "cfdef:valid_first_characters": "first", "cfdef:help_text": "help", "cfdef:list_heading_text": "listhead", @@ -100,7 +99,7 @@ def __init__( "kerb": { "kerb:validate_addresses": "checkaddrs", "kerb:default_ticket_life": "deftktlife", - "kerb:encryption_algorithm": "encrypt", + "kerb:encryption_algorithms": "encrypt", "kerb:realm_name": "kerbname", "kerb:max_ticket_life": "maxtktlf", "kerb:min_ticket_life": "mintklife", @@ -115,7 +114,7 @@ def __init__( "icsf:asymetric_key_usage": "asymusage", }, "ictx": { - "ictx:use_eim": "domap", + "ictx:use_identity_map": "domap", "ictx:require_identity_mapping": "mapreq", "ictx:identity_map_timeout": "maptimeo", "ictx:cache_application_provided_identity_map": "usemap", @@ -167,8 +166,8 @@ def __init__( "stdata:user": "racf:user", }, "svfmr": { - "svfmr:parameter_list": "racf:parmname", - "svfmr:script": "racf:script", + "svfmr:parameter_list_name": "racf:parmname", + "svfmr:script_name": "racf:script", }, "tme": { "tme:children": "racf:children", diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 9302885c..27ec45b8 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -156,7 +156,7 @@ def __init__( "tso:message_class": "msgclass", "tso:logon_procedure": "proc", "tso:security_label": "seclabel", - "tso:region_size": "size", + "tso:default_region_size": "size", "tso:sysout_class": "sysclass", "tso:data_set_allocation_unit": "unit", "tso:user_data": "userdata", @@ -189,10 +189,11 @@ def __init__( }, "tso": { "acctnum": "accountNumber", + "holdclass": "holdClass", "jobclass": "jobClass", "msgclass": "messageClass", "proc": "logonProcedure", - "size": "regionSize", + "size": "defaultRegionSize", "maxsize": "maxRegionSize", "sysoutclass": "sysoutClass", "unit": "dataSetAllocationUnit", @@ -200,6 +201,7 @@ def __init__( "command": "logonCommand", }, } + self._case_sensitive_extracted_values = ["homeDirectory", "defaultShell"] super().__init__( "user", debug=debug, @@ -272,7 +274,7 @@ def take_away_auditor_authority(self, userid: str) -> Union[dict, bytes]: def set_password( self, userid: str, - password: str, + password: Union[str, bool], ) -> Union[dict, bytes]: """Set a user's password.""" result = self.alter(userid, traits={"base:password": password}) @@ -284,7 +286,7 @@ def set_password( def set_passphrase( self, userid: str, - passphrase: str, + passphrase: Union[str, bool], ) -> Union[dict, bytes]: """Set a user's passphrase.""" result = self.alter(userid, traits={"base:passphrase": passphrase}) @@ -574,10 +576,10 @@ def get_omvs_default_shell(self, userid: str) -> Union[str, None, bytes]: def set_omvs_default_shell( self, userid: str, - program: Union[str, bool], + default_shell: Union[str, bool], ) -> Union[dict, bytes]: """Set a user's OMVS default shell.""" - result = self.alter(userid, traits={"omvs:default_shell": program}) + result = self.alter(userid, traits={"omvs:default_shell": default_shell}) return self._to_steps(result) # ============================================================================ @@ -685,18 +687,20 @@ def set_tso_logon_procedure( # ============================================================================ # TSO Region Size # ============================================================================ - def get_tso_region_size(self, userid: str) -> Union[int, None, bytes]: + def get_tso_default_region_size(self, userid: str) -> Union[int, None, bytes]: """Get a user's TSO region size.""" profile = self.extract(userid, segments={"tso": True}, profile_only=True) - return self._get_field(profile, "tso", "regionSize") + return self._get_field(profile, "tso", "defaultRegionSize") - def set_tso_region_size( + def set_tso_default_region_size( self, userid: str, - region_size: Union[int, bool], + default_region_size: Union[int, bool], ) -> Union[dict, bytes]: """Set a user's TSO region size.""" - result = self.alter(userid, traits={"tso:region_size": region_size}) + result = self.alter( + userid, traits={"tso:default_region_size": default_region_size} + ) return self._to_steps(result) # ============================================================================ diff --git a/tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.json b/tests/group/group_result_samples/extract_group_result_base_only_success.json similarity index 100% rename from tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.json rename to tests/group/group_result_samples/extract_group_result_base_only_success.json diff --git a/tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.xml b/tests/group/group_result_samples/extract_group_result_base_only_success.xml similarity index 100% rename from tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.xml rename to tests/group/group_result_samples/extract_group_result_base_only_success.xml diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index 671ba3fc..9da4f7d6 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -42,11 +42,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_DICTIONARY = get_sample( "extract_group_result_base_omvs_error.json" ) -TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML = get_sample( - "extract_group_result_base_only_no_omvs_success.xml" +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_group_result_base_only_success.xml" ) -TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON = get_sample( - "extract_group_result_base_only_no_omvs_success.json" +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_JSON = get_sample( + "extract_group_result_base_only_success.json" ) # Delete Group diff --git a/tests/group/test_group_getters.py b/tests/group/test_group_getters.py index a8e42493..25177201 100644 --- a/tests/group/test_group_getters.py +++ b/tests/group/test_group_getters.py @@ -27,7 +27,7 @@ def test_group_admin_has_group_special_authority_returns_true_when_group_special call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertTrue( self.group_admin.has_group_special_authority("TESTGRP0", "ESWIFT") @@ -63,7 +63,7 @@ def test_group_admin_has_group_operations_authority_returns_true_when_group_oper call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertTrue( self.group_admin.has_group_operations_authority("TESTGRP0", "LEONARD") @@ -99,7 +99,7 @@ def test_group_admin_has_group_auditor_authority_returns_true_when_group_auditor call_racf_mock: Mock, ): group_extract_auditor = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) group_extract_auditor = group_extract_auditor.replace( " CONNECT ATTRIBUTES=SPECIAL", @@ -115,7 +115,7 @@ def test_group_admin_has_group_auditor_authority_returns_false_when_not_group_au call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertFalse( self.group_admin.has_group_auditor_authority("TESTGRP0", "ESWIFT") @@ -140,7 +140,7 @@ def test_group_admin_has_group_access_attribute_returns_true_when_grpacc( call_racf_mock: Mock, ): group_extract_grpacc = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) group_extract_grpacc = group_extract_grpacc.replace( " CONNECT ATTRIBUTES=OPERATIONS", @@ -156,7 +156,7 @@ def test_group_admin_has_group_access_attribute_returns_false_when_not_grpacc( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertFalse( self.group_admin.has_group_access_attribute("TESTGRP0", "LEONARD") @@ -201,7 +201,7 @@ def test_group_admin_get_omvs_gid_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.group_admin.get_omvs_gid("TESTGRP0")) @@ -237,6 +237,6 @@ def test_group_admin_get_ovm_gid_returns_none_when_no_ovm_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.group_admin.get_ovm_gid("TESTGRP0")) diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 8a2f63cb..de98adb8 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -101,16 +101,16 @@ def test_group_admin_can_parse_extract_group_base_omvs_success_xml( TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) - def test_group_admin_can_parse_extract_group_base_only_no_omvs_success_xml( + def test_group_admin_can_parse_extract_group_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.group_admin.extract("TESTGRP0"), - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_JSON, ) # Error in environment, TESTGRP0 already deleted/not added diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 3f534166..2cb0c12c 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -76,11 +76,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_DICTIONARY = get_sample( "extract_user_result_base_omvs_error.json" ) -TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML = get_sample( - "extract_user_result_base_only_no_omvs_success.xml" +TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_user_result_base_only_success.xml" ) -TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON = get_sample( - "extract_user_result_base_only_no_omvs_success.json" +TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON = get_sample( + "extract_user_result_base_only_success.json" ) TEST_EXTRACT_USER_RESULT_WITH_CLASS_AUTHORIZATIONS = get_sample( "extract_user_result_with_class_authorizations.xml" @@ -88,7 +88,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample( "extract_user_result_with_command_audit_trail.xml" ) -TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML = get_sample( +TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML = get_sample( "extract_user_result_base_omvs_tso_revoke_resume.xml" ) TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY = get_sample( @@ -140,17 +140,17 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "omvs:max_processes": 128, "omvs:shared": True, "omvs:max_shared_memory": "2g", - "omvs:max_therads": 48, + "omvs:max_threads": 48, "omvs:uid": 1919, "omvs:home_directory": "/u/squidward", "omvs:default_shell": "/bin/sh", - "tso:account_number": "D999", + "tso:account_number": "SB29", "tso:logon_command": "ISPF", "tso:hold_class": "A", "tso:max_region_size": 2048, - "tso:message_class": "O", + "tso:message_class": "B", "tso:logon_procedure": "PROC", - "tso:region_size": 1024, + "tso:default_region_size": 1024, "tso:sysout_class": "O", "tso:user_data": "ABCD", "tso:data_set_allocation_unit": "SYSDA", @@ -190,6 +190,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # User Administration Setters Sample Data # ============================================================================ +# Base Segment TEST_USER_GIVE_SPECIAL_AUTHORITY_XML = get_sample( "user_give_special_authority_request.xml" ) @@ -209,7 +210,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "user_remove_operations_authority_request.xml" ) TEST_USER_SET_PASSWORD_XML = get_sample("user_set_password_request.xml") +TEST_USER_SET_PASSWORD_DELETE_XML = get_sample("user_set_password_delete_request.xml") TEST_USER_SET_PASSPHRASE_XML = get_sample("user_set_passphrase_request.xml") +TEST_USER_SET_PASSPHRASE_DELETE_XML = get_sample( + "user_set_passphrase_delete_request.xml" +) TEST_USER_ADD_CLASS_AUTHORIZATIONS_SINGLE_CLASS_XML = get_sample( "user_add_class_authorizations_single_class_request.xml" ) @@ -228,13 +233,135 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_USER_SET_CLASS_AUTHORIZATIONS_XML = get_sample( "user_set_class_authorizations_request.xml" ) +TEST_USER_SET_REVOKE_DATE_XML = get_sample("user_set_revoke_date_request.xml") +TEST_USER_SET_REVOKE_DATE_DELETE_XML = get_sample( + "user_set_revoke_date_delete_request.xml" +) +TEST_USER_SET_RESUME_DATE_XML = get_sample("user_set_resume_date_request.xml") +TEST_USER_SET_RESUME_DATE_DELETE_XML = get_sample( + "user_set_resume_date_delete_request.xml" +) +TEST_USER_SET_OWNER_XML = get_sample("user_set_owner_request.xml") +TEST_USER_SET_NAME_XML = get_sample("user_set_name_request.xml") +TEST_USER_SET_NAME_DELETE_XML = get_sample("user_set_name_delete_request.xml") + +# OMVS Segment TEST_USER_SET_OMVS_UID_XML = get_sample("user_set_omvs_uid_request.xml") +TEST_USER_SET_OMVS_UID_DELETE_XML = get_sample("user_set_omvs_uid_delete_request.xml") +TEST_USER_SET_OMVS_MAX_ADDRESS_SPACE_SIZE_XML = get_sample( + "user_set_omvs_max_address_space_size_request.xml" +) +TEST_USER_SET_OMVS_MAX_ADDRESS_SPACE_SIZE_DELETE_XML = get_sample( + "user_set_omvs_max_address_space_size_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_CPU_TIME_XML = get_sample( + "user_set_omvs_max_cpu_time_request.xml" +) +TEST_USER_SET_OMVS_MAX_CPU_TIME_DELETE_XML = get_sample( + "user_set_omvs_max_cpu_time_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_FILES_PER_PROCESS_XML = get_sample( + "user_set_omvs_max_files_per_process_request.xml" +) +TEST_USER_SET_OMVS_MAX_FILES_PER_PROCESS_DELETE_XML = get_sample( + "user_set_omvs_max_files_per_process_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_NON_SHARED_MEMORY_XML = get_sample( + "user_set_omvs_max_non_shared_memory_request.xml" +) +TEST_USER_SET_OMVS_MAX_NON_SHARED_MEMORY_DELETE_XML = get_sample( + "user_set_omvs_max_non_shared_memory_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_FILE_MAPPING_PAGES_XML = get_sample( + "user_set_omvs_max_file_mapping_pages_request.xml" +) +TEST_USER_SET_OMVS_MAX_FILE_MAPPING_PAGES_DELETE_XML = get_sample( + "user_set_omvs_max_file_mapping_pages_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_PROCESSES_XML = get_sample( + "user_set_omvs_max_processes_request.xml" +) +TEST_USER_SET_OMVS_MAX_PROCESSES_DELETE_XML = get_sample( + "user_set_omvs_max_processes_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_SHARED_MEMORY_XML = get_sample( + "user_set_omvs_max_shared_memory_request.xml" +) +TEST_USER_SET_OMVS_MAX_SHARED_MEMORY_DELETE_XML = get_sample( + "user_set_omvs_max_shared_memory_delete_request.xml" +) +TEST_USER_SET_OMVS_MAX_THREADS_XML = get_sample("user_set_omvs_max_threads_request.xml") +TEST_USER_SET_OMVS_MAX_THREADS_DELETE_XML = get_sample( + "user_set_omvs_max_threads_delete_request.xml" +) TEST_USER_SET_OMVS_HOME_DIRECTORY_XML = get_sample( "user_set_omvs_home_directory_request.xml" ) +TEST_USER_SET_OMVS_HOME_DIRECTORY_DELETE_XML = get_sample( + "user_set_omvs_home_directory_delete_request.xml" +) TEST_USER_SET_OMVS_DEFAULT_SHELL_XML = get_sample( "user_set_omvs_default_shell_request.xml" ) +TEST_USER_SET_OMVS_DEFAULT_SHELL_DELETE_XML = get_sample( + "user_set_omvs_default_shell_delete_request.xml" +) + +# TSO Segment +TEST_USER_SET_TSO_ACCOUNT_NUMBER_XML = get_sample( + "user_set_tso_account_number_request.xml" +) +TEST_USER_SET_TSO_ACCOUNT_NUMBER_DELETE_XML = get_sample( + "user_set_tso_account_number_delete_request.xml" +) +TEST_USER_SET_TSO_LOGON_COMMAND_XML = get_sample( + "user_set_tso_logon_command_request.xml" +) +TEST_USER_SET_TSO_LOGON_COMMAND_DELETE_XML = get_sample( + "user_set_tso_logon_command_delete_request.xml" +) +TEST_USER_SET_TSO_HOLD_CLASS_XML = get_sample("user_set_tso_hold_class_request.xml") +TEST_USER_SET_TSO_HOLD_CLASS_DELETE_XML = get_sample( + "user_set_tso_hold_class_delete_request.xml" +) +TEST_USER_SET_TSO_MAX_REGION_SIZE_XML = get_sample( + "user_set_tso_max_region_size_request.xml" +) +TEST_USER_SET_TSO_MAX_REGION_SIZE_DELETE_XML = get_sample( + "user_set_tso_max_region_size_delete_request.xml" +) +TEST_USER_SET_TSO_MESSAGE_CLASS_XML = get_sample( + "user_set_tso_message_class_request.xml" +) +TEST_USER_SET_TSO_MESSAGE_CLASS_DELETE_XML = get_sample( + "user_set_tso_message_class_delete_request.xml" +) +TEST_USER_SET_TSO_LOGON_PROCEDURE_XML = get_sample( + "user_set_tso_logon_procedure_request.xml" +) +TEST_USER_SET_TSO_LOGON_PROCEDURE_DELETE_XML = get_sample( + "user_set_tso_logon_procedure_delete_request.xml" +) +TEST_USER_SET_TSO_DEFAULT_REGION_SIZE_XML = get_sample( + "user_set_tso_default_region_size_request.xml" +) +TEST_USER_SET_TSO_DEFAULT_REGION_SIZE_DELETE_XML = get_sample( + "user_set_tso_default_region_size_delete_request.xml" +) +TEST_USER_SET_TSO_SYSOUT_CLASS_XML = get_sample("user_set_tso_sysout_class_request.xml") +TEST_USER_SET_TSO_SYSOUT_CLASS_DELETE_XML = get_sample( + "user_set_tso_sysout_class_delete_request.xml" +) +TEST_USER_SET_TSO_USER_DATA_XML = get_sample("user_set_tso_user_data_request.xml") +TEST_USER_SET_TSO_USER_DATA_DELETE_XML = get_sample( + "user_set_tso_user_data_delete_request.xml" +) +TEST_USER_SET_TSO_DATA_SET_ALLOCATION_UNIT_XML = get_sample( + "user_set_tso_data_set_allocation_unit_request.xml" +) +TEST_USER_SET_TSO_DATA_SET_ALLOCATION_UNIT_DELETE_XML = get_sample( + "user_set_tso_data_set_allocation_unit_delete_request.xml" +) # ============================================================================ # Debug Logging diff --git a/tests/user/test_user_getters.py b/tests/user/test_user_getters.py index 24313b68..f184cb11 100644 --- a/tests/user/test_user_getters.py +++ b/tests/user/test_user_getters.py @@ -151,7 +151,7 @@ def test_user_admin_get_class_authorizations_returns_empty_list_when_no_class_au call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual(self.user_admin.get_class_authorizations("squidwrd"), []) @@ -165,6 +165,90 @@ def test_user_admin_get_class_authorizations_raises_an_exception_when_extract_fa with self.assertRaises(SecurityRequestError): self.user_admin.get_class_authorizations("squidwrd") + # ============================================================================ + # Revoke Date + # ============================================================================ + def test_user_admin_get_revoke_date_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_revoke_date("squidwrd"), "10/22/2023") + + def test_user_admin_get_revoke_date_returns_none_when_there_is_no_revoke_date( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ) + self.assertEqual(self.user_admin.get_revoke_date("squidwrd"), None) + + # ============================================================================ + # Resume Date + # ============================================================================ + def test_user_admin_get_resume_date_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_resume_date("squidwrd"), "11/2/2023") + + def test_user_admin_get_resume_date_returns_none_when_there_is_no_resume_date( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ) + self.assertEqual(self.user_admin.get_resume_date("squidwrd"), None) + + # ============================================================================ + # Owner + # ============================================================================ + def test_user_admin_get_owner_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_owner("squidwrd"), "leonard") + + def test_user_admin_get_owner_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("OWNER=LEONARD", "OWNER=12345678") + self.assertEqual(self.user_admin.get_owner("squidwrd"), "12345678") + + # ============================================================================ + # Name + # ============================================================================ + def test_user_admin_get_name_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_name("squidwrd"), "squidward") + + def test_user_admin_get_name_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("NAME=SQUIDWARD", "NAME=12345678") + self.assertEqual(self.user_admin.get_name("squidwrd"), "12345678") + # ============================================================================ # OMVS UID # ============================================================================ @@ -192,25 +276,162 @@ def test_user_admin_get_omvs_uid_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.user_admin.get_omvs_uid("squidwrd")) # ============================================================================ - # OMVS Home + # OMVS Max Address Space Size # ============================================================================ - def test_user_admin_get_omvs_home_directory_works( + def test_user_admin_get_omvs_max_address_space_size_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual( + self.user_admin.get_omvs_max_address_space_size("squidwrd"), 10485760 + ) + + def test_user_admin_get_omvs_max_address_space_size_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_address_space_size("squidwrd") + + def test_user_admin_get_omvs_max_address_space_size_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_address_space_size("squidwrd")) + + # ============================================================================ + # OMVS Max CPU Time + # ============================================================================ + def test_user_admin_get_omvs_max_cpu_time_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_omvs_max_cpu_time("squidwrd"), 1500) + + def test_user_admin_get_omvs_max_cpu_time_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_cpu_time("squidwrd") + + def test_user_admin_get_omvs_max_cpu_time_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_cpu_time("squidwrd")) + + # ============================================================================ + # OMVS Max CPU Time + # ============================================================================ + def test_user_admin_get_omvs_max_files_per_process_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_omvs_max_files_per_process("squidwrd"), 50) + + def test_user_admin_get_omvs_max_files_per_process_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_files_per_process("squidwrd") + + def test_user_admin_get_omvs_max_files_per_process_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_files_per_process("squidwrd")) + + # ============================================================================ + # OMVS Max Non-Shared Memory + # ============================================================================ + def test_user_admin_get_omvs_max_non_shared_memory_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual( + self.user_admin.get_omvs_max_non_shared_memory("squidwrd"), "4g" + ) + + def test_user_admin_get_omvs_max_non_shared_memory_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_non_shared_memory("squidwrd") + + def test_user_admin_get_omvs_max_non_shared_memory_returns_none_when_field_is_unset( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML ) + self.assertIsNone(self.user_admin.get_omvs_max_non_shared_memory("squidwrd")) + + def test_user_admin_get_omvs_max_non_shared_memory_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_non_shared_memory("squidwrd")) + + # ============================================================================ + # OMVS Max File Mapping Pages + # ============================================================================ + def test_user_admin_get_omvs_max_file_mapping_pages_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) self.assertEqual( - self.user_admin.get_omvs_home_directory("squidwrd"), "/u/squidwrd" + self.user_admin.get_omvs_max_file_mapping_pages("squidwrd"), 350 ) - def test_user_admin_get_omvs_home_directory_raises_an_exception_when_extract_fails( + def test_user_admin_get_omvs_max_file_mapping_pages_raises_an_exception_when_extract_fails( self, call_racf_mock: Mock, ): @@ -218,30 +439,101 @@ def test_user_admin_get_omvs_home_directory_raises_an_exception_when_extract_fai TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError): - self.user_admin.get_omvs_home_directory("squidwrd") + self.user_admin.get_omvs_max_file_mapping_pages("squidwrd") - def test_user_admin_get_omvs_home_directory_returns_none_when_no_omvs_segment_exists( + def test_user_admin_get_omvs_max_file_mapping_pages_returns_none_when_no_omvs_segment_exists( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) - self.assertIsNone(self.user_admin.get_omvs_home_directory("squidwrd")) + self.assertIsNone(self.user_admin.get_omvs_max_file_mapping_pages("squidwrd")) # ============================================================================ - # OMVS Program + # OMVS Max Processes # ============================================================================ - def test_user_admin_get_omvs_default_shell_works( + def test_user_admin_get_omvs_max_processes_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_omvs_max_processes("squidwrd"), 128) + + def test_user_admin_get_omvs_max_processes_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_processes("squidwrd") + + def test_user_admin_get_omvs_max_processes_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_processes("squidwrd")) + + # ============================================================================ + # OMVS Max Shared Memory + # ============================================================================ + def test_user_admin_get_omvs_max_shared_memory_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_omvs_max_shared_memory("squidwrd"), "2g") + + def test_user_admin_get_omvs_max_shared_memory_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_max_shared_memory("squidwrd") + + def test_user_admin_get_omvs_max_shared_memory_returns_none_when_field_is_unset( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML ) - self.assertEqual(self.user_admin.get_omvs_default_shell("squidwrd"), "/bin/sh") + self.assertIsNone(self.user_admin.get_omvs_max_shared_memory("squidwrd")) - def test_user_admin_get_omvs_default_shell_raises_an_exception_when_extract_fails( + def test_user_admin_get_omvs_max_shared_memory_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_shared_memory("squidwrd")) + + # ============================================================================ + # OMVS Max Threads + # ============================================================================ + def test_user_admin_get_omvs_max_threads_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_omvs_max_threads("squidwrd"), 48) + + def test_user_admin_get_omvs_max_threads_raises_an_exception_when_extract_fails( self, call_racf_mock: Mock, ): @@ -249,13 +541,503 @@ def test_user_admin_get_omvs_default_shell_raises_an_exception_when_extract_fail TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError): - self.user_admin.get_omvs_default_shell("squidwrd") + self.user_admin.get_omvs_max_threads("squidwrd") - def test_user_admin_get_omvs_default_shell_returns_none_when_no_omvs_segment_exists( + def test_user_admin_get_omvs_max_threads_returns_none_when_no_omvs_segment_exists( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_threads("squidwrd")) + + # ============================================================================ + # OMVS Home Directory + # ============================================================================ + def test_user_admin_get_omvs_home_directory_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ) + self.assertEqual( + self.user_admin.get_omvs_home_directory("squidwrd"), "/u/squidwrd" + ) + + def test_user_admin_get_omvs_home_directory_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_home_directory("squidwrd") + + def test_user_admin_get_omvs_home_directory_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_home_directory("squidwrd")) + + def test_user_admin_get_omvs_home_directory_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("HOME= /u/squidwrd", "HOME= 12345678") + self.assertEqual( + self.user_admin.get_omvs_home_directory("squidwrd"), "12345678" + ) + + def test_user_admin_get_omvs_home_directory_handles_case_sensitivity_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("HOME= /u/squidwrd", "HOME= /u/SQUIDWRD") + self.assertEqual( + self.user_admin.get_omvs_home_directory("squidwrd"), "/u/SQUIDWRD" + ) + + # ============================================================================ + # OMVS Program + # ============================================================================ + def test_user_admin_get_omvs_default_shell_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ) + self.assertEqual(self.user_admin.get_omvs_default_shell("squidwrd"), "/bin/sh") + + def test_user_admin_get_omvs_default_shell_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_omvs_default_shell("squidwrd") + + def test_user_admin_get_omvs_default_shell_returns_none_when_no_omvs_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_default_shell("squidwrd")) + + def test_user_admin_get_omvs_default_shell_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("PROGRAM= /bin/sh", "PROGRAM= 12345678") + self.assertEqual(self.user_admin.get_omvs_default_shell("squidwrd"), "12345678") + + def test_user_admin_get_omvs_default_shell_handles_case_sensitivity_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML + ).replace("PROGRAM= /bin/sh", "PROGRAM= /BIN/sh") + self.assertEqual(self.user_admin.get_omvs_default_shell("squidwrd"), "/BIN/sh") + + # ============================================================================ + # TSO Account Number + # ============================================================================ + def test_user_admin_get_tso_account_number_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_account_number("squidwrd"), "sb29") + + def test_user_admin_get_tso_account_number_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_account_number("squidwrd") + + def test_user_admin_get_tso_account_number_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_account_number("squidwrd")) + + def test_user_admin_get_tso_account_number_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("ACCTNUM= SB29", "ACCTNUM= 1234") + self.assertEqual(self.user_admin.get_tso_account_number("squidwrd"), "1234") + + # ============================================================================ + # TSO Logon Command + # ============================================================================ + def test_user_admin_get_tso_logon_command_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_logon_command("squidwrd"), "ispf") + + def test_user_admin_get_tso_logon_command_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_logon_command("squidwrd") + + def test_user_admin_get_tso_logon_command_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_logon_command("squidwrd")) + + def test_user_admin_get_tso_logon_command_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("COMMAND= ISPF", "COMMAND= 1234") + self.assertEqual(self.user_admin.get_tso_logon_command("squidwrd"), "1234") + + # ============================================================================ + # TSO Hold Class + # ============================================================================ + def test_user_admin_get_tso_hold_class_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_hold_class("squidwrd"), "a") + + def test_user_admin_get_tso_hold_class_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_hold_class("squidwrd") + + def test_user_admin_get_tso_hold_class_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_hold_class("squidwrd")) + + def test_user_admin_get_tso_hold_class_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("HOLDCLASS= A", "HOLDCLASS= 1") + self.assertEqual(self.user_admin.get_tso_hold_class("squidwrd"), "1") + + # ============================================================================ + # TSO Max Region size + # ============================================================================ + def test_user_admin_get_tso_max_region_size_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_max_region_size("squidwrd"), 2048) + + def test_user_admin_get_tso_max_region_size_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_max_region_size("squidwrd") + + def test_user_admin_get_tso_max_region_size_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_max_region_size("squidwrd")) + + # ============================================================================ + # TSO Message Class + # ============================================================================ + def test_user_admin_get_tso_message_class_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_message_class("squidwrd"), "b") + + def test_user_admin_get_tso_message_class_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_message_class("squidwrd") + + def test_user_admin_get_tso_message_class_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_message_class("squidwrd")) + + def test_user_admin_get_tso_message_class_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("MSGCLASS= B", "MSGCLASS= 1") + self.assertEqual(self.user_admin.get_tso_message_class("squidwrd"), "1") + + # ============================================================================ + # TSO Logon Procedure + # ============================================================================ + def test_user_admin_get_tso_logon_procedure_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_logon_procedure("squidwrd"), "proc") + + def test_user_admin_get_tso_logon_procedure_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_logon_procedure("squidwrd") + + def test_user_admin_get_tso_logon_procedure_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_logon_procedure("squidwrd")) + + def test_user_admin_get_tso_logon_procedure_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("PROC= PROC", "PROC= 1234") + self.assertEqual(self.user_admin.get_tso_logon_procedure("squidwrd"), "1234") + + # ============================================================================ + # TSO Default Region size + # ============================================================================ + def test_user_admin_get_tso_region_size_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_default_region_size("squidwrd"), 1024) + + def test_user_admin_get_tso_default_region_size_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_default_region_size("squidwrd") + + def test_user_admin_get_default_tso_region_size_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_default_region_size("squidwrd")) + + # ============================================================================ + # TSO Sysout Class + # ============================================================================ + def test_user_admin_get_tso_sysout_class_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_sysout_class("squidwrd"), "o") + + def test_user_admin_get_tso_sysout_class_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_sysout_class("squidwrd") + + def test_user_admin_get_tso_sysout_class_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_sysout_class("squidwrd")) + + def test_user_admin_get_tso_sysout_class_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("SYSOUTCLASS= O", "SYSOUTCLASS= 1") + self.assertEqual(self.user_admin.get_tso_sysout_class("squidwrd"), "1") + + # ============================================================================ + # TSO User Data + # ============================================================================ + def test_user_admin_get_tso_user_data_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual(self.user_admin.get_tso_user_data("squidwrd"), "abcd") + + def test_user_admin_get_tso_user_data_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_user_data("squidwrd") + + def test_user_admin_get_tso_user_data_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_user_data("squidwrd")) + + def test_user_admin_get_tso_user_data_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("USERDATA= ABCD", "USERDATA= 1234") + self.assertEqual(self.user_admin.get_tso_user_data("squidwrd"), "1234") + + # ============================================================================ + # TSO User Data + # ============================================================================ + def test_user_admin_get_tso_data_set_allocation_unit_works( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual( + self.user_admin.get_tso_data_set_allocation_unit("squidwrd"), "sysda" + ) + + def test_user_admin_get_tso_data_set_allocation_unit_raises_an_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.user_admin.get_tso_data_set_allocation_unit("squidwrd") + + def test_user_admin_get_tso_data_set_allocation_unit_returns_none_when_no_tso_segment_exists( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_tso_data_set_allocation_unit("squidwrd")) + + def test_user_admin_get_tso_data_set_allocation_unit_handles_non_string_value_properly( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ).replace("UNIT= SYSDA", "UNIT= 1234") + self.assertEqual( + self.user_admin.get_tso_data_set_allocation_unit("squidwrd"), "1234" ) - self.assertIsNone(self.user_admin.get_omvs_default_shell("squidwrd")) diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 99501a82..2b5d44c9 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -101,16 +101,16 @@ def test_user_admin_can_parse_extract_user_base_omvs_success_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) - def test_user_admin_can_parse_extract_user_base_only_no_omvs_success_xml( + def test_user_admin_can_parse_extract_user_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.user_admin.extract("squidwrd", segments={"omvs": True}), - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON, ) # Error in environment, SQUIDWRD already deleted/not added @@ -145,7 +145,7 @@ def test_user_admin_can_parse_extract_user_base_omvs_tso_revoke_resume_success_x call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML ) self.assertEqual( self.user_admin.extract("squidwrd", segments={"omvs": True, "tso": True}), diff --git a/tests/user/test_user_setters.py b/tests/user/test_user_setters.py index 93900ee6..44ccf112 100644 --- a/tests/user/test_user_setters.py +++ b/tests/user/test_user_setters.py @@ -68,6 +68,10 @@ def test_user_admin_build_set_password_request(self): result = self.user_admin.set_password("squidwrd", "GIyTTqdF") self.assertEqual(result, TestUserConstants.TEST_USER_SET_PASSWORD_XML) + def test_user_admin_build_set_password_delete_request(self): + result = self.user_admin.set_password("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_PASSWORD_DELETE_XML) + # ============================================================================ # Passphrase # ============================================================================ @@ -75,6 +79,10 @@ def test_user_admin_build_set_passphrase_request(self): result = self.user_admin.set_passphrase("squidwrd", "PassPhrasesAreCool!") self.assertEqual(result, TestUserConstants.TEST_USER_SET_PASSPHRASE_XML) + def test_user_admin_build_set_passphrase_delete_request(self): + result = self.user_admin.set_passphrase("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_PASSPHRASE_DELETE_XML) + # ============================================================================ # Class Authorizations # ============================================================================ @@ -170,6 +178,46 @@ def test_user_admin_build_set_class_authorizations_no_existinsg_class_authorizat result, TestUserConstants.TEST_USER_SET_CLASS_AUTHORIZATIONS_XML ) + # ============================================================================ + # Revoke Date + # ============================================================================ + def test_user_admin_build_set_revoke_date_request(self): + result = self.user_admin.set_revoke_date("squidwrd", "10/22/23") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_REVOKE_DATE_XML) + + def test_user_admin_build_set_revoke_date_delete_request(self): + result = self.user_admin.set_revoke_date("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_REVOKE_DATE_DELETE_XML) + + # ============================================================================ + # Resume Date + # ============================================================================ + def test_user_admin_build_set_resume_date_request(self): + result = self.user_admin.set_resume_date("squidwrd", "11/2/23") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_RESUME_DATE_XML) + + def test_user_admin_build_set_resume_date_delete_request(self): + result = self.user_admin.set_resume_date("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_RESUME_DATE_DELETE_XML) + + # ============================================================================ + # Owner + # ============================================================================ + def test_user_admin_build_set_owner_request(self): + result = self.user_admin.set_owner("squidwrd", "leonard") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OWNER_XML) + + # ============================================================================ + # Name + # ============================================================================ + def test_user_admin_build_set_name_request(self): + result = self.user_admin.set_name("squidwrd", "Squidward") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_NAME_XML) + + def test_user_admin_build_set_name_delete_request(self): + result = self.user_admin.set_name("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_NAME_DELETE_XML) + # ============================================================================ # OMVS UID # ============================================================================ @@ -177,8 +225,130 @@ def test_user_admin_build_set_omvs_uid_request(self): result = self.user_admin.set_omvs_uid("squidwrd", 40) self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_UID_XML) + def test_user_admin_build_set_omvs_uid_delete_request(self): + result = self.user_admin.set_omvs_uid("squidwrd", False) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_UID_DELETE_XML) + + # ============================================================================ + # OMVS Max Address Space Size + # ============================================================================ + def test_user_admin_build_set_omvs_max_address_space_size_request(self): + result = self.user_admin.set_omvs_max_address_space_size("squidwrd", 10485760) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_ADDRESS_SPACE_SIZE_XML + ) + + def test_user_admin_build_set_max_address_space_size_delete_request(self): + result = self.user_admin.set_omvs_max_address_space_size("squidwrd", False) + self.assertEqual( + result, + TestUserConstants.TEST_USER_SET_OMVS_MAX_ADDRESS_SPACE_SIZE_DELETE_XML, + ) + + # ============================================================================ + # OMVS Max CPU Time + # ============================================================================ + def test_user_admin_build_set_omvs_max_cpu_time_request(self): + result = self.user_admin.set_omvs_max_cpu_time("squidwrd", 1500) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_MAX_CPU_TIME_XML) + + def test_user_admin_build_set_max_cpu_time_delete_request(self): + result = self.user_admin.set_omvs_max_cpu_time("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_CPU_TIME_DELETE_XML + ) + + # ============================================================================ + # OMVS Max Files Per Process + # ============================================================================ + def test_user_admin_build_set_omvs_max_files_per_process_request(self): + result = self.user_admin.set_omvs_max_files_per_process("squidwrd", 50) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_FILES_PER_PROCESS_XML + ) + + def test_user_admin_build_set_max_files_per_process_delete_request(self): + result = self.user_admin.set_omvs_max_files_per_process("squidwrd", False) + self.assertEqual( + result, + TestUserConstants.TEST_USER_SET_OMVS_MAX_FILES_PER_PROCESS_DELETE_XML, + ) + + # ============================================================================ + # OMVS Max Non-Shared Memory + # ============================================================================ + def test_user_admin_build_set_omvs_max_non_shared_memory_request(self): + result = self.user_admin.set_omvs_max_non_shared_memory("squidwrd", "4g") + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_NON_SHARED_MEMORY_XML + ) + + def test_user_admin_build_set_max_non_shared_memory_delete_request(self): + result = self.user_admin.set_omvs_max_non_shared_memory("squidwrd", False) + self.assertEqual( + result, + TestUserConstants.TEST_USER_SET_OMVS_MAX_NON_SHARED_MEMORY_DELETE_XML, + ) + + # ============================================================================ + # OMVS Max File Mapping Pages # ============================================================================ - # OMVS Home + def test_user_admin_build_set_omvs_max_file_mapping_pages_request(self): + result = self.user_admin.set_omvs_max_file_mapping_pages("squidwrd", 350) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_FILE_MAPPING_PAGES_XML + ) + + def test_user_admin_build_set_max_file_mapping_pages_delete_request(self): + result = self.user_admin.set_omvs_max_file_mapping_pages("squidwrd", False) + self.assertEqual( + result, + TestUserConstants.TEST_USER_SET_OMVS_MAX_FILE_MAPPING_PAGES_DELETE_XML, + ) + + # ============================================================================ + # OMVS Max Processes + # ============================================================================ + def test_user_admin_build_set_omvs_max_processes_request(self): + result = self.user_admin.set_omvs_max_processes("squidwrd", 128) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_MAX_PROCESSES_XML) + + def test_user_admin_build_set_omvs_max_processes_delete_request(self): + result = self.user_admin.set_omvs_max_processes("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_PROCESSES_DELETE_XML + ) + + # ============================================================================ + # OMVS Max Shared Memory + # ============================================================================ + def test_user_admin_build_set_omvs_max_shared_memory_request(self): + result = self.user_admin.set_omvs_max_shared_memory("squidwrd", "2g") + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_SHARED_MEMORY_XML + ) + + def test_user_admin_build_set_omvs_max_shared_memory_delete_request(self): + result = self.user_admin.set_omvs_max_shared_memory("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_SHARED_MEMORY_DELETE_XML + ) + + # ============================================================================ + # OMVS Max Threads + # ============================================================================ + def test_user_admin_build_set_omvs_max_threads_request(self): + result = self.user_admin.set_omvs_max_threads("squidwrd", 48) + self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_MAX_THREADS_XML) + + def test_user_admin_build_set_omvs_max_threads_delete_request(self): + result = self.user_admin.set_omvs_max_threads("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_MAX_THREADS_DELETE_XML + ) + + # ============================================================================ + # OMVS Home Directory # ============================================================================ def test_user_admin_build_set_omvs_home_directory_request(self): result = self.user_admin.set_omvs_home_directory("squidwrd", "/u/squidwrd") @@ -186,9 +356,160 @@ def test_user_admin_build_set_omvs_home_directory_request(self): result, TestUserConstants.TEST_USER_SET_OMVS_HOME_DIRECTORY_XML ) + def test_user_admin_build_set_omvs_home_directory_delete_request(self): + result = self.user_admin.set_omvs_home_directory("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_HOME_DIRECTORY_DELETE_XML + ) + # ============================================================================ - # OMVS Program + # OMVS Default Shell # ============================================================================ def test_user_admin_build_set_omvs_default_shell_request(self): result = self.user_admin.set_omvs_default_shell("squidwrd", "/bin/sh") self.assertEqual(result, TestUserConstants.TEST_USER_SET_OMVS_DEFAULT_SHELL_XML) + + def test_user_admin_build_set_omvs_default_shell_delete_request(self): + result = self.user_admin.set_omvs_default_shell("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_OMVS_DEFAULT_SHELL_DELETE_XML + ) + + # ============================================================================ + # TSO Account Number + # ============================================================================ + def test_user_admin_build_set_tso_account_number_request(self): + result = self.user_admin.set_tso_account_number("squidwrd", "SB29") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_ACCOUNT_NUMBER_XML) + + def test_user_admin_build_set_tso_account_number_delete_request(self): + result = self.user_admin.set_tso_account_number("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_ACCOUNT_NUMBER_DELETE_XML + ) + + # ============================================================================ + # TSO Logon Command + # ============================================================================ + def test_user_admin_build_set_tso_logon_command_request(self): + result = self.user_admin.set_tso_logon_command("squidwrd", "ISPF") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_LOGON_COMMAND_XML) + + def test_user_admin_build_set_tso_logon_command_delete_request(self): + result = self.user_admin.set_tso_logon_command("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_LOGON_COMMAND_DELETE_XML + ) + + # ============================================================================ + # TSO Hold Class + # ============================================================================ + def test_user_admin_build_set_tso_hold_class_request(self): + result = self.user_admin.set_tso_hold_class("squidwrd", "A") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_HOLD_CLASS_XML) + + def test_user_admin_build_set_tso_hold_class_delete_request(self): + result = self.user_admin.set_tso_hold_class("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_HOLD_CLASS_DELETE_XML + ) + + # ============================================================================ + # TSO Max Region Size + # ============================================================================ + def test_user_admin_build_set_tso_max_region_size_request(self): + result = self.user_admin.set_tso_max_region_size("squidwrd", 2048) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_MAX_REGION_SIZE_XML + ) + + def test_user_admin_build_set_tso_max_region_size_delete_request(self): + result = self.user_admin.set_tso_max_region_size("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_MAX_REGION_SIZE_DELETE_XML + ) + + # ============================================================================ + # TSO Message Class + # ============================================================================ + def test_user_admin_build_set_tso_message_class_request(self): + result = self.user_admin.set_tso_message_class("squidwrd", "B") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_MESSAGE_CLASS_XML) + + def test_user_admin_build_set_tso_message_class_delete_request(self): + result = self.user_admin.set_tso_message_class("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_MESSAGE_CLASS_DELETE_XML + ) + + # ============================================================================ + # TSO Logon Procedure + # ============================================================================ + def test_user_admin_build_set_tso_logon_procedure_request(self): + result = self.user_admin.set_tso_logon_procedure("squidwrd", "PROC") + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_LOGON_PROCEDURE_XML + ) + + def test_user_admin_build_set_tso_logon_procedure_delete_request(self): + result = self.user_admin.set_tso_logon_procedure("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_LOGON_PROCEDURE_DELETE_XML + ) + + # ============================================================================ + # TSO Region Size + # ============================================================================ + def test_user_admin_build_set_tso_default_region_size_request(self): + result = self.user_admin.set_tso_default_region_size("squidwrd", 2048) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_DEFAULT_REGION_SIZE_XML + ) + + def test_user_admin_build_set_tso_default_region_size_delete_request(self): + result = self.user_admin.set_tso_default_region_size("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_DEFAULT_REGION_SIZE_DELETE_XML + ) + + # ============================================================================ + # TSO Sysout Class + # ============================================================================ + def test_user_admin_build_set_tso_sysout_class_request(self): + result = self.user_admin.set_tso_sysout_class("squidwrd", "O") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_SYSOUT_CLASS_XML) + + def test_user_admin_build_set_tso_sysout_class_delete_request(self): + result = self.user_admin.set_tso_sysout_class("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_SYSOUT_CLASS_DELETE_XML + ) + + # ============================================================================ + # TSO User Data + # ============================================================================ + def test_user_admin_build_set_tso_user_data_request(self): + result = self.user_admin.set_tso_user_data("squidwrd", "ABCD") + self.assertEqual(result, TestUserConstants.TEST_USER_SET_TSO_USER_DATA_XML) + + def test_user_admin_build_set_tso_user_data_delete_request(self): + result = self.user_admin.set_tso_user_data("squidwrd", False) + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_USER_DATA_DELETE_XML + ) + + # ============================================================================ + # TSO Data Set Allocation Unit + # ============================================================================ + def test_user_admin_build_set_tso_data_set_allocation_unit_request(self): + result = self.user_admin.set_tso_data_set_allocation_unit("squidwrd", "SYSDA") + self.assertEqual( + result, TestUserConstants.TEST_USER_SET_TSO_DATA_SET_ALLOCATION_UNIT_XML + ) + + def test_user_admin_build_set_tso_data_set_allocation_unit_delete_request(self): + result = self.user_admin.set_tso_data_set_allocation_unit("squidwrd", False) + self.assertEqual( + result, + TestUserConstants.TEST_USER_SET_TSO_DATA_SET_ALLOCATION_UNIT_DELETE_XML, + ) diff --git a/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml index a69e7455..d40ce005 100644 --- a/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml +++ b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml @@ -16,16 +16,17 @@ 128 2g + 48 1919 /u/squidward /bin/sh - D999 + SB29 ISPF A 2048 - O + B PROC 1024 O diff --git a/tests/user/user_request_samples/user_set_name_delete_request.xml b/tests/user/user_request_samples/user_set_name_delete_request.xml new file mode 100644 index 00000000..50b40f3d --- /dev/null +++ b/tests/user/user_request_samples/user_set_name_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_name_request.xml b/tests/user/user_request_samples/user_set_name_request.xml new file mode 100644 index 00000000..005db431 --- /dev/null +++ b/tests/user/user_request_samples/user_set_name_request.xml @@ -0,0 +1,8 @@ + + + + Squidward + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_default_shell_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_default_shell_delete_request.xml new file mode 100644 index 00000000..4af3eab9 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_default_shell_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_home_directory_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_home_directory_delete_request.xml new file mode 100644 index 00000000..efc612a1 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_home_directory_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_address_space_size_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_address_space_size_delete_request.xml new file mode 100644 index 00000000..519e2428 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_address_space_size_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_address_space_size_request.xml b/tests/user/user_request_samples/user_set_omvs_max_address_space_size_request.xml new file mode 100644 index 00000000..4c55e811 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_address_space_size_request.xml @@ -0,0 +1,7 @@ + + + + 10485760 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_cpu_time_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_cpu_time_delete_request.xml new file mode 100644 index 00000000..4f33c46f --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_cpu_time_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_cpu_time_request.xml b/tests/user/user_request_samples/user_set_omvs_max_cpu_time_request.xml new file mode 100644 index 00000000..aac3429f --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_cpu_time_request.xml @@ -0,0 +1,7 @@ + + + + 1500 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_delete_request.xml new file mode 100644 index 00000000..d95bae3e --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_request.xml b/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_request.xml new file mode 100644 index 00000000..d202aece --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_file_mapping_pages_request.xml @@ -0,0 +1,7 @@ + + + + 350 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_files_per_process_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_files_per_process_delete_request.xml new file mode 100644 index 00000000..5d268230 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_files_per_process_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_files_per_process_request.xml b/tests/user/user_request_samples/user_set_omvs_max_files_per_process_request.xml new file mode 100644 index 00000000..55444cde --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_files_per_process_request.xml @@ -0,0 +1,7 @@ + + + + 50 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_delete_request.xml new file mode 100644 index 00000000..7c60bcea --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_request.xml b/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_request.xml new file mode 100644 index 00000000..ab456c3a --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_non_shared_memory_request.xml @@ -0,0 +1,7 @@ + + + + 4g + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_processes_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_processes_delete_request.xml new file mode 100644 index 00000000..81ab9ae3 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_processes_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_processes_request.xml b/tests/user/user_request_samples/user_set_omvs_max_processes_request.xml new file mode 100644 index 00000000..97f894b5 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_processes_request.xml @@ -0,0 +1,8 @@ + + + + 128 + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_shared_memory_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_shared_memory_delete_request.xml new file mode 100644 index 00000000..d728557e --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_shared_memory_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_shared_memory_request.xml b/tests/user/user_request_samples/user_set_omvs_max_shared_memory_request.xml new file mode 100644 index 00000000..3099f84d --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_shared_memory_request.xml @@ -0,0 +1,7 @@ + + + + 2g + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_threads_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_max_threads_delete_request.xml new file mode 100644 index 00000000..b596172f --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_threads_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_max_threads_request.xml b/tests/user/user_request_samples/user_set_omvs_max_threads_request.xml new file mode 100644 index 00000000..b317063d --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_max_threads_request.xml @@ -0,0 +1,7 @@ + + + + 48 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_omvs_uid_delete_request.xml b/tests/user/user_request_samples/user_set_omvs_uid_delete_request.xml new file mode 100644 index 00000000..68ab3e20 --- /dev/null +++ b/tests/user/user_request_samples/user_set_omvs_uid_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_owner_request.xml b/tests/user/user_request_samples/user_set_owner_request.xml new file mode 100644 index 00000000..3261161f --- /dev/null +++ b/tests/user/user_request_samples/user_set_owner_request.xml @@ -0,0 +1,7 @@ + + + + leonard + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_passphrase_delete_request.xml b/tests/user/user_request_samples/user_set_passphrase_delete_request.xml new file mode 100644 index 00000000..4c0abd56 --- /dev/null +++ b/tests/user/user_request_samples/user_set_passphrase_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_password_delete_request.xml b/tests/user/user_request_samples/user_set_password_delete_request.xml new file mode 100644 index 00000000..2a8962ce --- /dev/null +++ b/tests/user/user_request_samples/user_set_password_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_resume_date_delete_request.xml b/tests/user/user_request_samples/user_set_resume_date_delete_request.xml new file mode 100644 index 00000000..e812fb66 --- /dev/null +++ b/tests/user/user_request_samples/user_set_resume_date_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_resume_date_request.xml b/tests/user/user_request_samples/user_set_resume_date_request.xml new file mode 100644 index 00000000..b69d572b --- /dev/null +++ b/tests/user/user_request_samples/user_set_resume_date_request.xml @@ -0,0 +1,7 @@ + + + + 11/2/23 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_revoke_date_delete_request.xml b/tests/user/user_request_samples/user_set_revoke_date_delete_request.xml new file mode 100644 index 00000000..0693f8dd --- /dev/null +++ b/tests/user/user_request_samples/user_set_revoke_date_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_revoke_date_request.xml b/tests/user/user_request_samples/user_set_revoke_date_request.xml new file mode 100644 index 00000000..cc122c1b --- /dev/null +++ b/tests/user/user_request_samples/user_set_revoke_date_request.xml @@ -0,0 +1,8 @@ + + + + 10/22/23 + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_account_number_delete_request.xml b/tests/user/user_request_samples/user_set_tso_account_number_delete_request.xml new file mode 100644 index 00000000..d1ece33a --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_account_number_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_account_number_request.xml b/tests/user/user_request_samples/user_set_tso_account_number_request.xml new file mode 100644 index 00000000..600d2afa --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_account_number_request.xml @@ -0,0 +1,8 @@ + + + + SB29 + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_delete_request.xml b/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_delete_request.xml new file mode 100644 index 00000000..d7713794 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_request.xml b/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_request.xml new file mode 100644 index 00000000..3d4648e5 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_data_set_allocation_unit_request.xml @@ -0,0 +1,7 @@ + + + + SYSDA + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_default_region_size_delete_request.xml b/tests/user/user_request_samples/user_set_tso_default_region_size_delete_request.xml new file mode 100644 index 00000000..0c711819 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_default_region_size_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_default_region_size_request.xml b/tests/user/user_request_samples/user_set_tso_default_region_size_request.xml new file mode 100644 index 00000000..4bde1fdd --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_default_region_size_request.xml @@ -0,0 +1,7 @@ + + + + 2048 + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_hold_class_delete_request.xml b/tests/user/user_request_samples/user_set_tso_hold_class_delete_request.xml new file mode 100644 index 00000000..54dae79b --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_hold_class_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_hold_class_request.xml b/tests/user/user_request_samples/user_set_tso_hold_class_request.xml new file mode 100644 index 00000000..972238c5 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_hold_class_request.xml @@ -0,0 +1,8 @@ + + + + A + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_logon_command_delete_request.xml b/tests/user/user_request_samples/user_set_tso_logon_command_delete_request.xml new file mode 100644 index 00000000..55c642c1 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_logon_command_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_logon_command_request.xml b/tests/user/user_request_samples/user_set_tso_logon_command_request.xml new file mode 100644 index 00000000..ae2cd925 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_logon_command_request.xml @@ -0,0 +1,7 @@ + + + + ISPF + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_logon_procedure_delete_request.xml b/tests/user/user_request_samples/user_set_tso_logon_procedure_delete_request.xml new file mode 100644 index 00000000..596d0fe3 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_logon_procedure_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_logon_procedure_request.xml b/tests/user/user_request_samples/user_set_tso_logon_procedure_request.xml new file mode 100644 index 00000000..bd703853 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_logon_procedure_request.xml @@ -0,0 +1,7 @@ + + + + PROC + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_max_region_size_delete_request.xml b/tests/user/user_request_samples/user_set_tso_max_region_size_delete_request.xml new file mode 100644 index 00000000..d9c4fede --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_max_region_size_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_max_region_size_request.xml b/tests/user/user_request_samples/user_set_tso_max_region_size_request.xml new file mode 100644 index 00000000..332da1b4 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_max_region_size_request.xml @@ -0,0 +1,8 @@ + + + + 2048 + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_message_class_delete_request.xml b/tests/user/user_request_samples/user_set_tso_message_class_delete_request.xml new file mode 100644 index 00000000..52074177 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_message_class_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_message_class_request.xml b/tests/user/user_request_samples/user_set_tso_message_class_request.xml new file mode 100644 index 00000000..54594ea4 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_message_class_request.xml @@ -0,0 +1,7 @@ + + + + B + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_sysout_class_delete_request.xml b/tests/user/user_request_samples/user_set_tso_sysout_class_delete_request.xml new file mode 100644 index 00000000..bf1167e6 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_sysout_class_delete_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_sysout_class_request.xml b/tests/user/user_request_samples/user_set_tso_sysout_class_request.xml new file mode 100644 index 00000000..f66140e5 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_sysout_class_request.xml @@ -0,0 +1,7 @@ + + + + O + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_user_data_delete_request.xml b/tests/user/user_request_samples/user_set_tso_user_data_delete_request.xml new file mode 100644 index 00000000..b90165a3 --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_user_data_delete_request.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/user/user_request_samples/user_set_tso_user_data_request.xml b/tests/user/user_request_samples/user_set_tso_user_data_request.xml new file mode 100644 index 00000000..334e354b --- /dev/null +++ b/tests/user/user_request_samples/user_set_tso_user_data_request.xml @@ -0,0 +1,8 @@ + + + + ABCD + + + + \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json index 817d728d..dba8b1a7 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json @@ -14,7 +14,7 @@ { "base": { "user": "squidwrd", - "name": "squidwrd", + "name": "squidward", "owner": "leonard", "created": "10/21/2023", "defaultGroup": "sys1", @@ -53,17 +53,17 @@ "maxAddressSpaceSize": 10485760, "maxFilesPerProcess": 50, "maxProcesses": 128, - "maxThreads": null, + "maxThreads": 48, "maxFileMappingPages": 350, "maxNonSharedMemory": "4g", "maxSharedMemory": "2g" }, "tso": { - "accountNumber": "d999", - "holdclass": "a", - "messageClass": "o", + "accountNumber": "sb29", + "holdClass": "a", + "messageClass": "b", "logonProcedure": "proc", - "regionSize": 1024, + "defaultRegionSize": 1024, "maxRegionSize": 2048, "sysoutClass": "o", "dataSetAllocationUnit": "sysda", diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml index f38c2573..38e1f9db 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml @@ -6,7 +6,7 @@ 0 0 LISTUSER SQUIDWRD OMVS TSO - USER=SQUIDWRD NAME=SQUIDWRD OWNER=LEONARD CREATED=23.294 + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.294 DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A ATTRIBUTES=NONE REVOKE DATE=OCTOBER 22, 2023 RESUME DATE=NOVEMBER 2, 2023 @@ -35,16 +35,16 @@ ASSIZEMAX= 0010485760 FILEPROCMAX= 00000050 PROCUSERMAX= 00000128 - THREADSMAX= NONE + THREADSMAX= 48 MMAPAREAMAX= 00000350 MEMLIMIT= 4G SHMEMMAX= 2G TSO INFORMATION --------------- - ACCTNUM= D999 + ACCTNUM= SB29 HOLDCLASS= A - MSGCLASS= O + MSGCLASS= B PROC= PROC SIZE= 00001024 MAXSIZE= 00002048 diff --git a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.json b/tests/user/user_result_samples/extract_user_result_base_only_success.json similarity index 100% rename from tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.json rename to tests/user/user_result_samples/extract_user_result_base_only_success.json diff --git a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.xml b/tests/user/user_result_samples/extract_user_result_base_only_success.xml similarity index 100% rename from tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.xml rename to tests/user/user_result_samples/extract_user_result_base_only_success.xml From d310c62b26890d1b4a08ad03e3c233cf9fa24d72 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Sun, 22 Oct 2023 13:24:41 -0400 Subject: [PATCH 36/72] Cleanup and make 'unknown' get interpreted as 'None' Signed-off-by: Leonard Carcaramo --- pyproject.toml | 2 +- pyracf/common/security_admin.py | 2 +- pyracf/user/user_admin.py | 24 +++++++++++-------- tests/user/test_user_constants.py | 4 ++-- tests/user/test_user_setters.py | 14 +++++------ .../extract_user_base_omvs_success.log | 2 +- ...move_all_class_authorizations_request.xml} | 0 ..._user_result_base_omvs_csdata_success.json | 2 +- ...extract_user_result_base_omvs_success.json | 2 +- ...er_result_base_omvs_tso_revoke_resume.json | 2 +- ...extract_user_result_base_only_success.json | 2 +- 11 files changed, 30 insertions(+), 26 deletions(-) rename tests/user/user_request_samples/{user_delete_all_class_authorizations_request.xml => user_remove_all_class_authorizations_request.xml} (100%) diff --git a/pyproject.toml b/pyproject.toml index 5822a2d5..39514cd9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ [tool.poetry] name="pyracf" - version="1.0a3" + version="1.0b1" description="Python interface to RACF using IRRSMO00 RACF Callable Service." license = "Apache-2.0" authors = [ diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 6ea6bc54..b9c4569c 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -691,7 +691,7 @@ def _cast_from_str( """Cast null values floats and integers.""" if not case_sensitive: value = value.lower() - if value in ("n/a", "none", "none specified", "no", "None"): + if value in ("n/a", "none", "none specified", "no", "None", "unknown"): return None if value in ( "in effect", diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 27ec45b8..96cdd11d 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -308,14 +308,14 @@ def set_class_authorizations( removes the user's current class authorizations and then recreates the class authorizations list using the list that the user provides. """ - delete_result = self.delete_all_class_authorizations(userid) + delete_result = self.remove_all_class_authorizations(userid) add_result = self.add_class_authorizations(userid, class_authorizations) return self._to_steps([delete_result, add_result]) def add_class_authorizations( self, userid: str, class_authorizations: Union[str, List[str]] ) -> Union[dict, bytes]: - """Add a class to a user's class authorizations.""" + """Add one or more classes to a user's class authorizations.""" result = self.alter( userid, traits={"add:base:class_authorizations": class_authorizations} ) @@ -324,14 +324,14 @@ def add_class_authorizations( def remove_class_authorizations( self, userid: str, class_authorizations: Union[str, List[str]] ) -> Union[dict, bytes]: - """Remove a class from a user's class authorizations.""" + """Remove one or more classes from a user's class authorizations.""" result = self.alter( userid, traits={"remove:base:class_authorizations": class_authorizations} ) return self._to_steps(result) - def delete_all_class_authorizations(self, userid: str) -> Union[dict, bool, bytes]: - """Delete all classes from a users class authorizations.""" + def remove_all_class_authorizations(self, userid: str) -> Union[dict, bool, bytes]: + """Remove all classes from a users class authorizations.""" current_class_authorizations = self.get_class_authorizations(userid) if not current_class_authorizations: return False @@ -345,7 +345,9 @@ def get_revoke_date(self, userid: str) -> Union[str, None, bytes]: profile = self.extract(userid, profile_only=True) return self._get_field(profile, "base", "revokeDate", string=True) - def set_revoke_date(self, userid: str, revoke_date: str) -> Union[dict, bytes]: + def set_revoke_date( + self, userid: str, revoke_date: Union[str, bool] + ) -> Union[dict, bytes]: """Set a user's revoke date.""" result = self.alter(userid, traits={"base:revoke_date": revoke_date}) return self._to_steps(result) @@ -358,7 +360,9 @@ def get_resume_date(self, userid: str) -> Union[str, None, bytes]: profile = self.extract(userid, profile_only=True) return self._get_field(profile, "base", "resumeDate", string=True) - def set_resume_date(self, userid: str, resume_date: str) -> Union[dict, bytes]: + def set_resume_date( + self, userid: str, resume_date: Union[str, bool] + ) -> Union[dict, bytes]: """Set a user's resume date.""" result = self.alter(userid, traits={"base:resume_date": resume_date}) return self._to_steps(result) @@ -685,10 +689,10 @@ def set_tso_logon_procedure( return self._to_steps(result) # ============================================================================ - # TSO Region Size + # TSO Default Region Size # ============================================================================ def get_tso_default_region_size(self, userid: str) -> Union[int, None, bytes]: - """Get a user's TSO region size.""" + """Get a user's TSO default region size.""" profile = self.extract(userid, segments={"tso": True}, profile_only=True) return self._get_field(profile, "tso", "defaultRegionSize") @@ -697,7 +701,7 @@ def set_tso_default_region_size( userid: str, default_region_size: Union[int, bool], ) -> Union[dict, bytes]: - """Set a user's TSO region size.""" + """Set a user's TSO default region size.""" result = self.alter( userid, traits={"tso:default_region_size": default_region_size} ) diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 2cb0c12c..4ef760cf 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -227,8 +227,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_USER_REMOVE_CLASS_AUTHORIZATIONS_MULTIPLE_CLASSES_XML = get_sample( "user_remove_class_authorizations_multiple_classes_request.xml" ) -TEST_USER_DELETE_ALL_CLASS_AUTHORIZATIONS_XML = get_sample( - "user_delete_all_class_authorizations_request.xml" +TEST_USER_REMOVE_ALL_CLASS_AUTHORIZATIONS_XML = get_sample( + "user_remove_all_class_authorizations_request.xml" ) TEST_USER_SET_CLASS_AUTHORIZATIONS_XML = get_sample( "user_set_class_authorizations_request.xml" diff --git a/tests/user/test_user_setters.py b/tests/user/test_user_setters.py index 44ccf112..5650aaa9 100644 --- a/tests/user/test_user_setters.py +++ b/tests/user/test_user_setters.py @@ -121,7 +121,7 @@ def test_user_admin_build_remove_class_authorizations_multiple_classes_request( ) @patch("pyracf.user.user_admin.UserAdmin.get_class_authorizations") - def test_user_admin_build_delete_all_class_authorizations_request( + def test_user_admin_build_remove_all_class_authorizations_request( self, get_class_authorizations_mock: Mock, ): @@ -130,18 +130,18 @@ def test_user_admin_build_delete_all_class_authorizations_request( "terminal", "xfacilit", ] - result = self.user_admin.delete_all_class_authorizations("squidwrd") + result = self.user_admin.remove_all_class_authorizations("squidwrd") self.assertEqual( - result, TestUserConstants.TEST_USER_DELETE_ALL_CLASS_AUTHORIZATIONS_XML + result, TestUserConstants.TEST_USER_REMOVE_ALL_CLASS_AUTHORIZATIONS_XML ) @patch("pyracf.user.user_admin.UserAdmin.get_class_authorizations") - def test_user_admin_build_delete_all_class_authorizations_request_returns_false_if_none( + def test_user_admin_build_remove_all_class_authorizations_request_returns_false_if_none( self, get_class_authorizations_mock: Mock, ): get_class_authorizations_mock.return_value = [] - result = self.user_admin.delete_all_class_authorizations("squidwrd") + result = self.user_admin.remove_all_class_authorizations("squidwrd") self.assertFalse(result) @patch("pyracf.user.user_admin.UserAdmin.get_class_authorizations") @@ -160,7 +160,7 @@ def test_user_admin_build_set_class_authorizations_request( self.assertEqual( result, ( - TestUserConstants.TEST_USER_DELETE_ALL_CLASS_AUTHORIZATIONS_XML + TestUserConstants.TEST_USER_REMOVE_ALL_CLASS_AUTHORIZATIONS_XML + TestUserConstants.TEST_USER_SET_CLASS_AUTHORIZATIONS_XML ), ) @@ -458,7 +458,7 @@ def test_user_admin_build_set_tso_logon_procedure_delete_request(self): ) # ============================================================================ - # TSO Region Size + # TSO Default Region Size # ============================================================================ def test_user_admin_build_set_tso_default_region_size_request(self): result = self.user_admin.set_tso_default_region_size("squidwrd", 2048) diff --git a/tests/user/user_log_samples/extract_user_base_omvs_success.log b/tests/user/user_log_samples/extract_user_base_omvs_success.log index feb9169d..1e82f6e9 100644 --- a/tests/user/user_log_samples/extract_user_base_omvs_success.log +++ b/tests/user/user_log_samples/extract_user_base_omvs_success.log @@ -175,7 +175,7 @@ "connectDate": "3/28/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null diff --git a/tests/user/user_request_samples/user_delete_all_class_authorizations_request.xml b/tests/user/user_request_samples/user_remove_all_class_authorizations_request.xml similarity index 100% rename from tests/user/user_request_samples/user_delete_all_class_authorizations_request.xml rename to tests/user/user_request_samples/user_remove_all_class_authorizations_request.xml diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json b/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json index 578a62a4..48671a57 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_csdata_success.json @@ -35,7 +35,7 @@ "connectDate": "6/6/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_success.json b/tests/user/user_result_samples/extract_user_result_base_omvs_success.json index 79ceb80d..c007bcc9 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_success.json @@ -37,7 +37,7 @@ "connectDate": "3/28/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json index dba8b1a7..c035e486 100644 --- a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json +++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json @@ -35,7 +35,7 @@ "connectDate": "10/21/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null diff --git a/tests/user/user_result_samples/extract_user_result_base_only_success.json b/tests/user/user_result_samples/extract_user_result_base_only_success.json index b6af8ec6..e7e9a089 100644 --- a/tests/user/user_result_samples/extract_user_result_base_only_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_only_success.json @@ -35,7 +35,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null From 94178eac2bd9d4a6a7bbbb9d7d4a462a1d5adb37 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Mon, 23 Oct 2023 12:38:44 -0400 Subject: [PATCH 37/72] Cleanup. Signed-off-by: Leonard Carcaramo --- pyproject.toml | 2 +- pyracf/user/user_admin.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 39514cd9..c702c629 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ repository = "https://github.com/ambitus/pyracf" documentation = "https://ambitus.github.io/pyracf/" classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Other", diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 96cdd11d..ec641527 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -383,7 +383,7 @@ def set_owner(self, userid: str, owner: str) -> Union[dict, bytes]: # ============================================================================ # Name # ============================================================================ - def get_name(self, userid: str) -> Union[str, bytes]: + def get_name(self, userid: str) -> Union[str, None, bytes]: """Get a user's name.""" profile = self.extract(userid, profile_only=True) return self._get_field(profile, "base", "name", string=True) From 50a23b5fa5676a48e31ace2eb867fdbcef7cd1f4 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Mon, 23 Oct 2023 15:36:18 -0400 Subject: [PATCH 38/72] Change extract segments to list instead of dictionary. Signed-off-by: Leonard Carcaramo --- pyracf/common/security_admin.py | 4 +-- pyracf/data_set/data_set_admin.py | 2 +- pyracf/group/group_admin.py | 6 ++-- pyracf/resource/resource_admin.py | 6 +++- pyracf/user/user_admin.py | 44 +++++++++++------------ tests/group/test_group_debug_logging.py | 4 +-- tests/group/test_group_request_builder.py | 2 +- tests/group/test_group_result_parser.py | 4 +-- tests/user/test_user_debug_logging.py | 4 +-- tests/user/test_user_request_builder.py | 4 +-- tests/user/test_user_result_parser.py | 12 +++---- 11 files changed, 47 insertions(+), 45 deletions(-) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index b9c4569c..b29b955e 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -258,11 +258,11 @@ def __validate_and_add_trait( self._trait_map[trait] = self._valid_segment_traits[segment][trait] return True - def _build_bool_segment_dictionaries(self, segments: dict) -> None: + def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: """Build segment dictionaries for profile extract.""" for segment in segments: if segment in self._valid_segment_traits: - self._segment_traits[segment] = segments[segment] + self._segment_traits[segment] = True # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index a95b065e..94f653f7 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -123,7 +123,7 @@ def alter( def extract( self, data_set: str, - segments: dict = {}, + segments: List[str] = [], volume: Union[str, None] = None, generic: bool = False, profile_only: bool = False, diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index f15f8bc4..610b4677 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -93,7 +93,7 @@ def has_group_access_attribute(self, group: str, userid: str) -> Union[bool, byt # ============================================================================ def get_omvs_gid(self, group: str) -> Union[int, bytes]: """Get a group's OMVS GID.""" - profile = self.extract(group, segments={"omvs": True}, profile_only=True) + profile = self.extract(group, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "gid") def set_omvs_gid(self, group: str, gid: int) -> Union[dict, bytes]: @@ -106,7 +106,7 @@ def set_omvs_gid(self, group: str, gid: int) -> Union[dict, bytes]: # ============================================================================ def get_ovm_gid(self, group: str) -> Union[int, bytes]: """Get a group's OVM GID.""" - profile = self.extract(group, segments={"ovm": True}, profile_only=True) + profile = self.extract(group, segments=["ovm"], profile_only=True) return self._get_field(profile, "ovm", "gid") def set_ovm_gid(self, group: str, gid: int) -> Union[dict, bytes]: @@ -132,7 +132,7 @@ def alter(self, group: str, traits: dict = {}) -> Union[dict, bytes]: return self._make_request(group_request, irrsmo00_precheck=True) def extract( - self, group: str, segments: dict = {}, profile_only: bool = False + self, group: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a group's profile.""" self._build_bool_segment_dictionaries(segments) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index c2f29ec2..55c90806 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -235,7 +235,11 @@ def alter( return self._make_request(profile_request, irrsmo00_precheck=True) def extract( - self, resource: str, class_name: str, segments={}, profile_only: bool = False + self, + resource: str, + class_name: str, + segments: List[str] = [], + profile_only: bool = False, ) -> Union[dict, bytes]: """Extract a general resource profile.""" self._build_bool_segment_dictionaries(segments) diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index ec641527..14aa45e5 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -398,7 +398,7 @@ def set_name(self, userid: str, name: Union[str, bool]) -> Union[dict, bytes]: # ============================================================================ def get_omvs_uid(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS UID.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "uid") def set_omvs_uid(self, userid: str, uid: Union[int, bool]) -> Union[dict, bytes]: @@ -411,7 +411,7 @@ def set_omvs_uid(self, userid: str, uid: Union[int, bool]) -> Union[dict, bytes] # ============================================================================ def get_omvs_max_address_space_size(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max address space size.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxAddressSpaceSize") def set_omvs_max_address_space_size( @@ -430,7 +430,7 @@ def set_omvs_max_address_space_size( # ============================================================================ def get_omvs_max_cpu_time(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max cpu time.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxCpuTime") def set_omvs_max_cpu_time( @@ -447,7 +447,7 @@ def set_omvs_max_cpu_time( # ============================================================================ def get_omvs_max_files_per_process(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max files per process.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxFilesPerProcess") def set_omvs_max_files_per_process( @@ -466,7 +466,7 @@ def set_omvs_max_files_per_process( # ============================================================================ def get_omvs_max_non_shared_memory(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS max non-shared memory.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxNonSharedMemory", string=True) def set_omvs_max_non_shared_memory( @@ -485,7 +485,7 @@ def set_omvs_max_non_shared_memory( # ============================================================================ def get_omvs_max_file_mapping_pages(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max file mapping pages.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxFileMappingPages") def set_omvs_max_file_mapping_pages( @@ -504,7 +504,7 @@ def set_omvs_max_file_mapping_pages( # ============================================================================ def get_omvs_max_processes(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max processes.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxProcesses") def set_omvs_max_processes( @@ -521,7 +521,7 @@ def set_omvs_max_processes( # ============================================================================ def get_omvs_max_shared_memory(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS max shared memory.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxSharedMemory", string=True) def set_omvs_max_shared_memory( @@ -540,7 +540,7 @@ def set_omvs_max_shared_memory( # ============================================================================ def get_omvs_max_threads(self, userid: str) -> Union[int, None, bytes]: """Get a user's OMVS max threads.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "maxThreads") def set_omvs_max_threads( @@ -557,7 +557,7 @@ def set_omvs_max_threads( # ============================================================================ def get_omvs_home_directory(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS home directory.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "homeDirectory", string=True) def set_omvs_home_directory( @@ -574,7 +574,7 @@ def set_omvs_home_directory( # ============================================================================ def get_omvs_default_shell(self, userid: str) -> Union[str, None, bytes]: """Get a user's OMVS default shell.""" - profile = self.extract(userid, segments={"omvs": True}, profile_only=True) + profile = self.extract(userid, segments=["omvs"], profile_only=True) return self._get_field(profile, "omvs", "defaultShell", string=True) def set_omvs_default_shell( @@ -591,7 +591,7 @@ def set_omvs_default_shell( # ============================================================================ def get_tso_account_number(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO account number.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "accountNumber", string=True) def set_tso_account_number( @@ -608,7 +608,7 @@ def set_tso_account_number( # ============================================================================ def get_tso_logon_command(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO logon command.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "logonCommand", string=True) def set_tso_logon_command( @@ -625,7 +625,7 @@ def set_tso_logon_command( # ============================================================================ def get_tso_hold_class(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO hold class.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "holdClass", string=True) def set_tso_hold_class( @@ -642,7 +642,7 @@ def set_tso_hold_class( # ============================================================================ def get_tso_max_region_size(self, userid: str) -> Union[int, None, bytes]: """Get a user's TSO max region size.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "maxRegionSize") def set_tso_max_region_size( @@ -659,7 +659,7 @@ def set_tso_max_region_size( # ============================================================================ def get_tso_message_class(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO message class.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "messageClass", string=True) def set_tso_message_class( @@ -676,7 +676,7 @@ def set_tso_message_class( # ============================================================================ def get_tso_logon_procedure(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO logon procedure.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "logonProcedure", string=True) def set_tso_logon_procedure( @@ -693,7 +693,7 @@ def set_tso_logon_procedure( # ============================================================================ def get_tso_default_region_size(self, userid: str) -> Union[int, None, bytes]: """Get a user's TSO default region size.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "defaultRegionSize") def set_tso_default_region_size( @@ -712,7 +712,7 @@ def set_tso_default_region_size( # ============================================================================ def get_tso_sysout_class(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO sysout class.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "sysoutClass", string=True) def set_tso_sysout_class( @@ -729,7 +729,7 @@ def set_tso_sysout_class( # ============================================================================ def get_tso_user_data(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO user data.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "userData", string=True) def set_tso_user_data( @@ -746,7 +746,7 @@ def set_tso_user_data( # ============================================================================ def get_tso_data_set_allocation_unit(self, userid: str) -> Union[str, None, bytes]: """Get a user's TSO data set allocation unit.""" - profile = self.extract(userid, segments={"tso": True}, profile_only=True) + profile = self.extract(userid, segments=["tso"], profile_only=True) return self._get_field(profile, "tso", "dataSetAllocationUnit", string=True) def set_tso_data_set_allocation_unit( @@ -778,7 +778,7 @@ def alter(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: return self._make_request(user_request, irrsmo00_precheck=True) def extract( - self, userid: str, segments: dict = {}, profile_only: bool = False + self, userid: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a user's profile.""" self._build_bool_segment_dictionaries(segments) diff --git a/tests/group/test_group_debug_logging.py b/tests/group/test_group_debug_logging.py index f0ddacd7..fad5e8f6 100644 --- a/tests/group/test_group_debug_logging.py +++ b/tests/group/test_group_debug_logging.py @@ -69,7 +69,7 @@ def test_extract_group_base_omvs_request_debug_log_works_on_success( ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.group_admin.extract("TESTGRP0", segments={"omvs": True}) + self.group_admin.extract("TESTGRP0", segments=["omvs"]) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( success_log, TestGroupConstants.TEST_EXTRACT_GROUP_BASE_OMVS_SUCCESS_LOG @@ -85,7 +85,7 @@ def test_extract_group_base_omvs_request_debug_log_works_on_error( stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.group_admin.extract("TESTGRP0", segments={"omvs": True}) + self.group_admin.extract("TESTGRP0", segments=["omvs"]) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) diff --git a/tests/group/test_group_request_builder.py b/tests/group/test_group_request_builder.py index 4d9f6749..ddd9ba86 100644 --- a/tests/group/test_group_request_builder.py +++ b/tests/group/test_group_request_builder.py @@ -31,7 +31,7 @@ def test_group_admin_build_alter_group_request(self): self.assertEqual(result, TestGroupConstants.TEST_ALTER_GROUP_REQUEST_XML) def test_group_admin_build_extract_group_request_base_omvs(self): - result = self.group_admin.extract("TESTGRP0", segments={"omvs": True}) + result = self.group_admin.extract("TESTGRP0", segments=["omvs"]) self.assertEqual( result, TestGroupConstants.TEST_EXTRACT_GROUP_REQUEST_BASE_OMVS_XML ) diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index de98adb8..a817b555 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -97,7 +97,7 @@ def test_group_admin_can_parse_extract_group_base_omvs_success_xml( TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_SUCCESS_XML ) self.assertEqual( - self.group_admin.extract("TESTGRP0", segments={"omvs": True}), + self.group_admin.extract("TESTGRP0", segments=["omvs"]), TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) @@ -122,7 +122,7 @@ def test_group_admin_can_parse_extract_group_base_omvs_error_xml( TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError) as exception: - self.group_admin.extract("TESTGRP0", segments={"omvs": True}) + self.group_admin.extract("TESTGRP0", segments=["omvs"]) self.assertEqual( exception.exception.result, TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_DICTIONARY, diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index 615959fa..ed5a132d 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -287,7 +287,7 @@ def test_extract_user_base_omvs_request_debug_log_works_on_success( ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.extract("squidwrd", segments={"omvs": True}) + self.user_admin.extract("squidwrd", segments=["omvs"]) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( success_log, TestUserConstants.TEST_EXTRACT_USER_BASE_OMVS_SUCCESS_LOG @@ -303,7 +303,7 @@ def test_extract_user_base_omvs_request_debug_log_works_on_error( stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.extract("squidwrd", segments={"omvs": True}) + self.user_admin.extract("squidwrd", segments=["omvs"]) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index a3e8d34a..743837c1 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -47,9 +47,7 @@ def test_user_admin_build_alter_user_request(self): self.assertEqual(result, TestUserConstants.TEST_ALTER_USER_REQUEST_XML) def test_user_admin_build_extract_user_request_base_omvs(self): - result = self.user_admin.extract( - "squidwrd", segments={"omvs": True, "mfa": False} - ) + result = self.user_admin.extract("squidwrd", segments=["omvs"]) self.assertEqual( result, TestUserConstants.TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML ) diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 2b5d44c9..1c8a75b9 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -97,7 +97,7 @@ def test_user_admin_can_parse_extract_user_base_omvs_success_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML ) self.assertEqual( - self.user_admin.extract("squidwrd", segments={"omvs": True}), + self.user_admin.extract("squidwrd", segments=["omvs"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) @@ -109,7 +109,7 @@ def test_user_admin_can_parse_extract_user_base_only_success_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( - self.user_admin.extract("squidwrd", segments={"omvs": True}), + self.user_admin.extract("squidwrd", segments=["omvs"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON, ) @@ -122,7 +122,7 @@ def test_user_admin_can_parse_extract_user_base_omvs_error_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML ) with self.assertRaises(SecurityRequestError) as exception: - self.user_admin.extract("squidwrd", segments={"omvs": True}) + self.user_admin.extract("squidwrd", segments=["omvs"]) self.assertEqual( exception.exception.result, TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_DICTIONARY, @@ -136,7 +136,7 @@ def test_user_admin_can_parse_extract_user_and_ignore_command_audit_trail_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML ) self.assertEqual( - self.user_admin.extract("squidwrd", segments={"omvs": True}), + self.user_admin.extract("squidwrd", segments=["omvs"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) @@ -148,7 +148,7 @@ def test_user_admin_can_parse_extract_user_base_omvs_tso_revoke_resume_success_x TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML ) self.assertEqual( - self.user_admin.extract("squidwrd", segments={"omvs": True, "tso": True}), + self.user_admin.extract("squidwrd", segments=["omvs", "tso"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY, ) @@ -365,6 +365,6 @@ def test_user_admin_can_parse_extract_user_base_omvs_csdata_success_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_CSDATA_SUCCESS_XML ) self.assertEqual( - user_admin.extract("squidwrd", {"omvs": True, "csdata": True}), + user_admin.extract("squidwrd", segments=["omvs", "csdata"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_CSDATA_SUCCESS_DICTIONARY, ) From 81e313b5dc3760d734a4512152e2cc39c28bac8f Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Mon, 23 Oct 2023 17:16:32 -0400 Subject: [PATCH 39/72] Name Changes and Segment Name Error Added Invalid Segment Name Error Pluralized SETROPTS gettrs/settrs and changed type hints Change name of alter connection and alter access Signed-off-by: Elijah Swift --- pyracf/__init__.py | 1 + pyracf/access/access_admin.py | 2 +- pyracf/common/invalid_segment_name_error.py | 18 +++ pyracf/common/security_admin.py | 7 + pyracf/connection/connection_admin.py | 20 +-- pyracf/setropts/setropts_admin.py | 134 +++++++++++------- ...cess_error.log => permit_access_error.log} | 8 +- ..._success.log => permit_access_success.log} | 8 +- ..._request.xml => permit_access_request.xml} | 0 ...r.json => permit_access_result_error.json} | 0 ...ror.xml => permit_access_result_error.xml} | 0 ...json => permit_access_result_success.json} | 0 ...s.xml => permit_access_result_success.xml} | 0 tests/access/test_access_constants.py | 18 +-- tests/access/test_access_debug_logging.py | 18 +-- tests/access/test_access_request_builder.py | 6 +- tests/access/test_access_result_parser.py | 16 +-- ...error.log => connect_connection_error.log} | 8 +- ...ess.log => connect_connection_success.log} | 8 +- ...est.xml => connect_connection_request.xml} | 0 ...n => connect_connection_result_error.json} | 0 ...ml => connect_connection_result_error.xml} | 0 ...=> connect_connection_result_success.json} | 0 ... => connect_connection_result_success.xml} | 0 tests/connection/test_connection_constants.py | 24 ++-- .../test_connection_debug_logging.py | 20 +-- .../test_connection_request_builder.py | 8 +- .../test_connection_result_parser.py | 20 +-- tests/setropts/test_setropts_setters.py | 34 ++--- tests/user/test_user_constants.py | 2 + tests/user/test_user_request_builder.py | 35 ++++- 31 files changed, 255 insertions(+), 160 deletions(-) create mode 100644 pyracf/common/invalid_segment_name_error.py rename tests/access/access_log_samples/{alter_access_error.log => permit_access_error.log} (92%) rename tests/access/access_log_samples/{alter_access_success.log => permit_access_success.log} (91%) rename tests/access/access_request_samples/{alter_access_request.xml => permit_access_request.xml} (100%) rename tests/access/access_result_samples/{alter_access_result_error.json => permit_access_result_error.json} (100%) rename tests/access/access_result_samples/{alter_access_result_error.xml => permit_access_result_error.xml} (100%) rename tests/access/access_result_samples/{alter_access_result_success.json => permit_access_result_success.json} (100%) rename tests/access/access_result_samples/{alter_access_result_success.xml => permit_access_result_success.xml} (100%) rename tests/connection/connection_log_samples/{alter_connection_error.log => connect_connection_error.log} (92%) rename tests/connection/connection_log_samples/{alter_connection_success.log => connect_connection_success.log} (91%) rename tests/connection/connection_request_samples/{alter_connection_request.xml => connect_connection_request.xml} (100%) rename tests/connection/connection_result_samples/{alter_connection_result_error.json => connect_connection_result_error.json} (100%) rename tests/connection/connection_result_samples/{alter_connection_result_error.xml => connect_connection_result_error.xml} (100%) rename tests/connection/connection_result_samples/{alter_connection_result_success.json => connect_connection_result_success.json} (100%) rename tests/connection/connection_result_samples/{alter_connection_result_success.xml => connect_connection_result_success.xml} (100%) diff --git a/pyracf/__init__.py b/pyracf/__init__.py index 379dd12b..44409d47 100644 --- a/pyracf/__init__.py +++ b/pyracf/__init__.py @@ -1,6 +1,7 @@ """Make security admin subclasses available from package root.""" from .access.access_admin import AccessAdmin from .common.alter_operation_error import AlterOperationError +from .common.invalid_segment_name_error import InvalidSegmentNameError from .common.invalid_segment_trait_error import InvalidSegmentTraitError from .common.security_request_error import SecurityRequestError from .connection.connection_admin import ConnectionAdmin diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index c226af20..9faef1c5 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -54,7 +54,7 @@ def __init__( # ============================================================================ # Base Functions # ============================================================================ - def alter( + def permit( self, resource: str, class_name: str, diff --git a/pyracf/common/invalid_segment_name_error.py b/pyracf/common/invalid_segment_name_error.py new file mode 100644 index 00000000..e8d08e69 --- /dev/null +++ b/pyracf/common/invalid_segment_name_error.py @@ -0,0 +1,18 @@ +"""Exception to use when the user passes invalid segment name(s) on an extract request.""" + + +class InvalidSegmentNameError(Exception): + """ + Raised when a user passes an invalid segment name on an extract request. + """ + + def __init__(self, invalid_segments: list) -> None: + self.message = "Building of Security Request failed.\n\n" + for segment in invalid_segments: + self.message += ( + "Could not find " + + f"'{segment}' in valid segments for the requested operation.\n" + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 020e3f17..677de6d3 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -5,6 +5,7 @@ from datetime import datetime from typing import Any, List, Tuple, Union +from .invalid_segment_name_error import InvalidSegmentNameError from .invalid_segment_trait_error import InvalidSegmentTraitError from .irrsmo00 import IRRSMO00 from .logger import Logger @@ -259,9 +260,15 @@ def __validate_and_add_trait( def _build_bool_segment_dictionaries(self, segments: dict) -> None: """Build segment dictionaries for profile extract.""" + invalid_segments = [] for segment in segments: if segment in self._valid_segment_traits: self._segment_traits[segment] = segments[segment] + else: + invalid_segments.append(segment) + + if invalid_segments: + raise InvalidSegmentNameError(invalid_segments) # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index fbfe902b..79005eca 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -54,14 +54,14 @@ def give_group_special_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Give a user RACF special authority within a group.""" - result = self.alter(userid, group, {"base:special": True}) + result = self.connect(userid, group, {"base:special": True}) return self._to_steps(result) def take_away_group_special_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Remove a user's RACF special authoritiy within a group.""" - result = self.alter(userid, group, {"base:special": False}) + result = self.connect(userid, group, {"base:special": False}) return self._to_steps(result) # ============================================================================ @@ -71,14 +71,14 @@ def give_group_operations_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Give a user operations authority within a group.""" - result = self.alter(userid, group, {"base:operations": True}) + result = self.connect(userid, group, {"base:operations": True}) return self._to_steps(result) def take_away_group_operations_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Remove a user's operations authority within a group.""" - result = self.alter(userid, group, {"base:operations": False}) + result = self.connect(userid, group, {"base:operations": False}) return self._to_steps(result) # ============================================================================ @@ -88,14 +88,14 @@ def give_group_auditor_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Give a user auditor authority within a group.""" - result = self.alter(userid, group, {"base:auditor": True}) + result = self.connect(userid, group, {"base:auditor": True}) return self._to_steps(result) def take_away_group_auditor_authority( self, userid: str, group: str ) -> Union[dict, bytes]: """Remove a user's auditor authority within a group.""" - result = self.alter(userid, group, {"base:auditor": False}) + result = self.connect(userid, group, {"base:auditor": False}) return self._to_steps(result) # ============================================================================ @@ -106,7 +106,7 @@ def set_group_access_attribute(self, userid: str, group: str) -> Union[dict, byt Automatically make group data set profiles that a user creates accessible to all members of the group. """ - result = self.alter(userid, group, {"base:group_access": True}) + result = self.connect(userid, group, {"base:group_access": True}) return self._to_steps(result) def remove_group_access_attribute( @@ -116,14 +116,14 @@ def remove_group_access_attribute( Don't automatically make group data set profiles that a user creates accessible to all members of the group. """ - result = self.alter(userid, group, {"base:group_access": False}) + result = self.connect(userid, group, {"base:group_access": False}) return self._to_steps(result) # ============================================================================ # Base Functions # ============================================================================ - def alter(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: - """Alter an existing group connection.""" + def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: + """Establish or change a group connection.""" self._build_segment_dictionaries(traits) connection_request = ConnectionRequest(userid, group, "set") self._add_traits_directly_to_request_xml_with_no_segments(connection_request) diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 5f47b071..677fefe7 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -124,9 +124,9 @@ def get_password_rules(self) -> Union[dict, bytes]: # ============================================================================ # Raclist Refresh # ============================================================================ - def refresh_raclist(self, class_name: str) -> Union[dict, bytes]: + def refresh_raclist(self, class_names: Union[List[str], str]) -> Union[dict, bytes]: """Refresh raclist.""" - result = self.alter(options={"base:raclist": class_name, "base:refresh": True}) + result = self.alter(options={"base:raclist": class_names, "base:refresh": True}) return self._to_steps(result) # ============================================================================ @@ -147,135 +147,161 @@ def get_class_attributes(self, class_name: str) -> Union[list, bytes]: # ============================================================================ # Audit Class # ============================================================================ - def add_audit_class(self, class_name: str) -> Union[dict, bytes]: - """Add a class to list of classes that RACF performs auditing for.""" - result = self.alter(options={"base:audit_class": class_name}) + def add_audit_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Add class(es) to list of classes that RACF performs auditing for.""" + result = self.alter(options={"base:audit_class": class_names}) return self._to_steps(result) - def remove_audit_class(self, class_name: str) -> Union[dict, bytes]: - """Remove a class from the list of classes that RACF performs auditing for.""" - result = self.alter(options={"delete:base:audit_class": class_name}) + def remove_audit_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Remove class(es) from the list of classes that RACF performs auditing for.""" + result = self.alter(options={"delete:base:audit_class": class_names}) return self._to_steps(result) # ============================================================================ # Active Class # ============================================================================ - def add_active_class(self, class_name: str) -> Union[dict, bytes]: + def add_active_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: """ - Add a class to the list of classes that RACF performs access authorization checking for. + Add class(es) to the list of classes that RACF performs access authorization checking for. """ - result = self.alter(options={"base:active_class": class_name}) + result = self.alter(options={"base:active_class": class_names}) return self._to_steps(result) - def remove_active_class(self, class_name: str) -> Union[dict, bytes]: + def remove_active_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: """ - Remove a class from the list of classes that + Remove class(es) from the list of classes that RACF performs access authorization checking for. """ - result = self.alter(options={"delete:base:active_class": class_name}) + result = self.alter(options={"delete:base:active_class": class_names}) return self._to_steps(result) # ============================================================================ # Statistics Class # ============================================================================ - def add_statistics_class(self, class_name: str) -> Union[dict, bytes]: - """Add a class to the list of classes that RACF collects statistics for.""" - result = self.alter(options={"base:statistics_class": class_name}) + def add_statistics_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Add class(es) to the list of classes that RACF collects statistics for.""" + result = self.alter(options={"base:statistics_class": class_names}) return self._to_steps(result) - def remove_statistics_class(self, class_name: str) -> Union[dict, bytes]: - """Remove a class from the list of classes that RACF collects statistics for.""" - result = self.alter(options={"delete:base:statistics_class": class_name}) + def remove_statistics_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Remove class(es) from the list of classes that RACF collects statistics for.""" + result = self.alter(options={"delete:base:statistics_class": class_names}) return self._to_steps(result) # ============================================================================ # Generic Command Processing Class # ============================================================================ - def add_generic_command_processing_class( - self, class_name: str + def add_generic_command_processing_classes( + self, class_names: Union[List[str], str] ) -> Union[dict, bytes]: """ - Add a class to the list of classes that have + Add class(es) to the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"base:general_command_class": class_name}) + result = self.alter(options={"base:general_command_class": class_names}) return self._to_steps(result) - def remove_generic_command_processing_class( - self, class_name: str + def remove_generic_command_processing_classes( + self, class_names: Union[List[str], str] ) -> Union[dict, bytes]: """ - Remove a class from the list of classes that + Remove class(es) from the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"delete:base:general_command_class": class_name}) + result = self.alter(options={"delete:base:general_command_class": class_names}) return self._to_steps(result) # ============================================================================ # Generic Profile Checking Class # ============================================================================ - def add_generic_profile_checking_class(self, class_name: str) -> Union[dict, bytes]: - """Add a class to the list of classes that have generic profile checking enabled.""" - result = self.alter(options={"base:generic_profile_checking_class": class_name}) + def add_generic_profile_checking_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Add class(es) to the list of classes that have generic profile checking enabled.""" + result = self.alter( + options={"base:generic_profile_checking_class": class_names} + ) return self._to_steps(result) - def remove_generic_profile_checking_class( - self, class_name: str + def remove_generic_profile_checking_classes( + self, class_names: Union[List[str], str] ) -> Union[dict, bytes]: - """Remove a class from the list of classes that have generic profile checking enabled.""" + """Remove class(es) from the list of classes that have generic profile checking enabled.""" result = self.alter( - options={"delete:base:generic_profile_checking_class": class_name} + options={"delete:base:generic_profile_checking_class": class_names} ) return self._to_steps(result) # ============================================================================ # Generic Profile Sharing Class # ============================================================================ - def add_generic_profile_sharing_class(self, class_name: str) -> Union[dict, bytes]: + def add_generic_profile_sharing_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: """ - Add a class to the list of classes that are eligible for + Add class(es) to the list of classes that are eligible for general resource profile sharing in common storage. """ - result = self.alter(options={"base:generic_profile_sharing_class": class_name}) + result = self.alter(options={"base:generic_profile_sharing_class": class_names}) return self._to_steps(result) - def remove_generic_profile_sharing_class( - self, class_name: str + def remove_generic_profile_sharing_classes( + self, class_names: Union[List[str], str] ) -> Union[dict, bytes]: """ - Remove a class from the list of classes that are eligible + Remove class(es) from the list of classes that are eligible for general resource profile sharing in common storage. """ result = self.alter( - options={"delete:base:generic_profile_sharing_class": class_name} + options={"delete:base:generic_profile_sharing_class": class_names} ) return self._to_steps(result) # ============================================================================ # Global Access Class # ============================================================================ - def add_global_access_class(self, class_name: str) -> Union[dict, bytes]: - """Add a class to the list of classes eligible for global access checking.""" - return self.alter(options={"base:global_access_class": class_name}) + def add_global_access_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Add class(es) to the list of classes eligible for global access checking.""" + return self.alter(options={"base:global_access_class": class_names}) - def remove_global_access_class(self, class_name: str) -> Union[dict, bytes]: - """Remove a class from the list of classes eligible for global access checking.""" - result = self.alter(options={"delete:base:global_access_class": class_name}) + def remove_global_access_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Remove class(es) from the list of classes eligible for global access checking.""" + result = self.alter(options={"delete:base:global_access_class": class_names}) return self._to_steps(result) # ============================================================================ # Raclist Class # ============================================================================ - def add_raclist_class(self, class_name: str) -> Union[dict, bytes]: - """Add a class to list of classes that have in-storage profile sharing activated.""" - result = self.alter(options={"base:raclist": class_name}) + def add_raclist_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: + """Add class(es) to list of classes that have in-storage profile sharing activated.""" + result = self.alter(options={"base:raclist": class_names}) return self._to_steps(result) - def remove_raclist_class(self, class_name: str) -> Union[dict, bytes]: + def remove_raclist_classes( + self, class_names: Union[List[str], str] + ) -> Union[dict, bytes]: """ - Remove a class from the list of classes that have in-storage profile sharing activated. + Remove class(es) from the list of classes that have in-storage profile sharing activated. """ - result = self.alter(options={"delete:base:raclist": class_name}) + result = self.alter(options={"delete:base:raclist": class_names}) return self._to_steps(result) # ============================================================================ diff --git a/tests/access/access_log_samples/alter_access_error.log b/tests/access/access_log_samples/permit_access_error.log similarity index 92% rename from tests/access/access_log_samples/alter_access_error.log rename to tests/access/access_log_samples/permit_access_error.log index 07d546f5..deaeaf6f 100644 --- a/tests/access/access_log_samples/alter_access_error.log +++ b/tests/access/access_log_samples/permit_access_error.log @@ -1,7 +1,7 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.alter() + AccessAdmin.permit() { @@ -20,7 +20,7 @@ [pyRACF:Debug] Request XML - AccessAdmin.alter() + AccessAdmin.permit() @@ -33,7 +33,7 @@ [pyRACF:Debug] Result XML - AccessAdmin.alter() + AccessAdmin.permit() @@ -54,7 +54,7 @@ [pyRACF:Debug] Result Dictionary - AccessAdmin.alter() + AccessAdmin.permit() { diff --git a/tests/access/access_log_samples/alter_access_success.log b/tests/access/access_log_samples/permit_access_success.log similarity index 91% rename from tests/access/access_log_samples/alter_access_success.log rename to tests/access/access_log_samples/permit_access_success.log index 36e5de83..f7440155 100644 --- a/tests/access/access_log_samples/alter_access_success.log +++ b/tests/access/access_log_samples/permit_access_success.log @@ -1,7 +1,7 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.alter() + AccessAdmin.permit() { @@ -20,7 +20,7 @@ [pyRACF:Debug] Request XML - AccessAdmin.alter() + AccessAdmin.permit() @@ -33,7 +33,7 @@ [pyRACF:Debug] Result XML - AccessAdmin.alter() + AccessAdmin.permit() @@ -53,7 +53,7 @@ [pyRACF:Debug] Result Dictionary - AccessAdmin.alter() + AccessAdmin.permit() { diff --git a/tests/access/access_request_samples/alter_access_request.xml b/tests/access/access_request_samples/permit_access_request.xml similarity index 100% rename from tests/access/access_request_samples/alter_access_request.xml rename to tests/access/access_request_samples/permit_access_request.xml diff --git a/tests/access/access_result_samples/alter_access_result_error.json b/tests/access/access_result_samples/permit_access_result_error.json similarity index 100% rename from tests/access/access_result_samples/alter_access_result_error.json rename to tests/access/access_result_samples/permit_access_result_error.json diff --git a/tests/access/access_result_samples/alter_access_result_error.xml b/tests/access/access_result_samples/permit_access_result_error.xml similarity index 100% rename from tests/access/access_result_samples/alter_access_result_error.xml rename to tests/access/access_result_samples/permit_access_result_error.xml diff --git a/tests/access/access_result_samples/alter_access_result_success.json b/tests/access/access_result_samples/permit_access_result_success.json similarity index 100% rename from tests/access/access_result_samples/alter_access_result_success.json rename to tests/access/access_result_samples/permit_access_result_success.json diff --git a/tests/access/access_result_samples/alter_access_result_success.xml b/tests/access/access_result_samples/permit_access_result_success.xml similarity index 100% rename from tests/access/access_result_samples/alter_access_result_success.xml rename to tests/access/access_result_samples/permit_access_result_success.xml diff --git a/tests/access/test_access_constants.py b/tests/access/test_access_constants.py index 846e2a23..d05d1774 100644 --- a/tests/access/test_access_constants.py +++ b/tests/access/test_access_constants.py @@ -16,12 +16,14 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter Access -TEST_ALTER_ACCESS_RESULT_SUCCESS_XML = get_sample("alter_access_result_success.xml") -TEST_ALTER_ACCESS_RESULT_SUCCESS_DICTIONARY = get_sample( - "alter_access_result_success.json" +TEST_PERMIT_ACCESS_RESULT_SUCCESS_XML = get_sample("permit_access_result_success.xml") +TEST_PERMIT_ACCESS_RESULT_SUCCESS_DICTIONARY = get_sample( + "permit_access_result_success.json" +) +TEST_PERMIT_ACCESS_RESULT_ERROR_XML = get_sample("permit_access_result_error.xml") +TEST_PERMIT_ACCESS_RESULT_ERROR_DICTIONARY = get_sample( + "permit_access_result_error.json" ) -TEST_ALTER_ACCESS_RESULT_ERROR_XML = get_sample("alter_access_result_error.xml") -TEST_ALTER_ACCESS_RESULT_ERROR_DICTIONARY = get_sample("alter_access_result_error.json") # Delete Access @@ -39,7 +41,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter Access -TEST_ALTER_ACCESS_REQUEST_XML = get_sample("alter_access_request.xml") +TEST_PERMIT_ACCESS_REQUEST_XML = get_sample("permit_access_request.xml") # Delete Access TEST_DELETE_ACCESS_REQUEST_XML = get_sample("delete_access_request.xml") @@ -48,5 +50,5 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ALTER_ACCESS_SUCCESS_LOG = get_sample("alter_access_success.log") -TEST_ALTER_ACCESS_ERROR_LOG = get_sample("alter_access_error.log") +TEST_PERMIT_ACCESS_SUCCESS_LOG = get_sample("permit_access_success.log") +TEST_PERMIT_ACCESS_ERROR_LOG = get_sample("permit_access_error.log") diff --git a/tests/access/test_access_debug_logging.py b/tests/access/test_access_debug_logging.py index 8de63c71..89f25964 100644 --- a/tests/access/test_access_debug_logging.py +++ b/tests/access/test_access_debug_logging.py @@ -26,35 +26,37 @@ class TestAccessDebugLogging(unittest.TestCase): # ============================================================================ # Alter Access # ============================================================================ - def test_alter_access_request_debug_log_works_on_success( + def test_permit_access_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_XML + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.access_admin.alter( + self.access_admin.permit( "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ) success_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(success_log, TestAccessConstants.TEST_ALTER_ACCESS_SUCCESS_LOG) + self.assertEqual( + success_log, TestAccessConstants.TEST_PERMIT_ACCESS_SUCCESS_LOG + ) - def test_alter_access_request_debug_log_works_on_error( + def test_permit_access_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_ERROR_XML + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.access_admin.alter( + self.access_admin.permit( "TESTING", "ELIJTEST", "MCGINLEY", traits={"base:access": "ALTER"} ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestAccessConstants.TEST_ALTER_ACCESS_ERROR_LOG) + self.assertEqual(error_log, TestAccessConstants.TEST_PERMIT_ACCESS_ERROR_LOG) diff --git a/tests/access/test_access_request_builder.py b/tests/access/test_access_request_builder.py index 1e1dd71f..4fbe20bc 100644 --- a/tests/access/test_access_request_builder.py +++ b/tests/access/test_access_request_builder.py @@ -18,11 +18,11 @@ class TestAccessRequestBuilder(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) access_admin = AccessAdmin(generate_requests_only=True) - def test_access_admin_build_alter_access_request(self): - result = self.access_admin.alter( + def test_access_admin_build_permit_access_request(self): + result = self.access_admin.permit( "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ) - self.assertEqual(result, TestAccessConstants.TEST_ALTER_ACCESS_REQUEST_XML) + self.assertEqual(result, TestAccessConstants.TEST_PERMIT_ACCESS_REQUEST_XML) def test_access_admin_build_delete_access_request(self): result = self.access_admin.delete("TESTING", "ELIJTEST", "ESWIFT") diff --git a/tests/access/test_access_result_parser.py b/tests/access/test_access_result_parser.py index 01c4ef27..f81c29ca 100644 --- a/tests/access/test_access_result_parser.py +++ b/tests/access/test_access_result_parser.py @@ -22,35 +22,35 @@ class TestAccessResultParser(unittest.TestCase): # ============================================================================ # Alter Access # ============================================================================ - def test_access_admin_can_parse_alter_access_success_xml( + def test_access_admin_can_parse_permit_access_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_XML + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_SUCCESS_XML ) self.assertEqual( - self.access_admin.alter( + self.access_admin.permit( "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ), - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_DICTIONARY, + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_SUCCESS_DICTIONARY, ) # Error, UserID MCGINLEY not defined to RACF - def test_access_admin_can_parse_alter_access_error_xml( + def test_access_admin_can_parse_permit_access_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_ERROR_XML + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_ERROR_XML ) with self.assertRaises(SecurityRequestError) as exception: - self.access_admin.alter( + self.access_admin.permit( "TESTING", "ELIJTEST", "MCGINLEY", traits={"base:access": "ALTER"} ) self.assertEqual( exception.exception.result, - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_ERROR_DICTIONARY, + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/connection/connection_log_samples/alter_connection_error.log b/tests/connection/connection_log_samples/connect_connection_error.log similarity index 92% rename from tests/connection/connection_log_samples/alter_connection_error.log rename to tests/connection/connection_log_samples/connect_connection_error.log index 00b44e8f..4fb7a2ba 100644 --- a/tests/connection/connection_log_samples/alter_connection_error.log +++ b/tests/connection/connection_log_samples/connect_connection_error.log @@ -1,7 +1,7 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.alter() + ConnectionAdmin.connect() { @@ -20,7 +20,7 @@ [pyRACF:Debug] Request XML - ConnectionAdmin.alter() + ConnectionAdmin.connect() @@ -33,7 +33,7 @@ [pyRACF:Debug] Result XML - ConnectionAdmin.alter() + ConnectionAdmin.connect() @@ -55,7 +55,7 @@ [pyRACF:Debug] Result Dictionary - ConnectionAdmin.alter() + ConnectionAdmin.connect() { diff --git a/tests/connection/connection_log_samples/alter_connection_success.log b/tests/connection/connection_log_samples/connect_connection_success.log similarity index 91% rename from tests/connection/connection_log_samples/alter_connection_success.log rename to tests/connection/connection_log_samples/connect_connection_success.log index 98c1a826..a25b4c01 100644 --- a/tests/connection/connection_log_samples/alter_connection_success.log +++ b/tests/connection/connection_log_samples/connect_connection_success.log @@ -1,7 +1,7 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.alter() + ConnectionAdmin.connect() { @@ -20,7 +20,7 @@ [pyRACF:Debug] Request XML - ConnectionAdmin.alter() + ConnectionAdmin.connect() @@ -33,7 +33,7 @@ [pyRACF:Debug] Result XML - ConnectionAdmin.alter() + ConnectionAdmin.connect() @@ -53,7 +53,7 @@ [pyRACF:Debug] Result Dictionary - ConnectionAdmin.alter() + ConnectionAdmin.connect() { diff --git a/tests/connection/connection_request_samples/alter_connection_request.xml b/tests/connection/connection_request_samples/connect_connection_request.xml similarity index 100% rename from tests/connection/connection_request_samples/alter_connection_request.xml rename to tests/connection/connection_request_samples/connect_connection_request.xml diff --git a/tests/connection/connection_result_samples/alter_connection_result_error.json b/tests/connection/connection_result_samples/connect_connection_result_error.json similarity index 100% rename from tests/connection/connection_result_samples/alter_connection_result_error.json rename to tests/connection/connection_result_samples/connect_connection_result_error.json diff --git a/tests/connection/connection_result_samples/alter_connection_result_error.xml b/tests/connection/connection_result_samples/connect_connection_result_error.xml similarity index 100% rename from tests/connection/connection_result_samples/alter_connection_result_error.xml rename to tests/connection/connection_result_samples/connect_connection_result_error.xml diff --git a/tests/connection/connection_result_samples/alter_connection_result_success.json b/tests/connection/connection_result_samples/connect_connection_result_success.json similarity index 100% rename from tests/connection/connection_result_samples/alter_connection_result_success.json rename to tests/connection/connection_result_samples/connect_connection_result_success.json diff --git a/tests/connection/connection_result_samples/alter_connection_result_success.xml b/tests/connection/connection_result_samples/connect_connection_result_success.xml similarity index 100% rename from tests/connection/connection_result_samples/alter_connection_result_success.xml rename to tests/connection/connection_result_samples/connect_connection_result_success.xml diff --git a/tests/connection/test_connection_constants.py b/tests/connection/test_connection_constants.py index 1541cbe7..4f5a34ea 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -16,15 +16,17 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter Connection -TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML = get_sample( - "alter_connection_result_success.xml" +TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML = get_sample( + "connect_connection_result_success.xml" ) -TEST_ALTER_CONNECTION_RESULT_SUCCESS_DICTIONARY = get_sample( - "alter_connection_result_success.json" +TEST_CONNECT_CONNECTION_RESULT_SUCCESS_DICTIONARY = get_sample( + "connect_connection_result_success.json" ) -TEST_ALTER_CONNECTION_RESULT_ERROR_XML = get_sample("alter_connection_result_error.xml") -TEST_ALTER_CONNECTION_RESULT_ERROR_DICTIONARY = get_sample( - "alter_connection_result_error.json" +TEST_CONNECT_CONNECTION_RESULT_ERROR_XML = get_sample( + "connect_connection_result_error.xml" +) +TEST_CONNECT_CONNECTION_RESULT_ERROR_DICTIONARY = get_sample( + "connect_connection_result_error.json" ) @@ -47,8 +49,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter Connection -TEST_ALTER_CONNECTION_REQUEST_XML = get_sample("alter_connection_request.xml") -TEST_ALTER_CONNECTION_REQUEST_TRAITS = { +TEST_CONNECT_CONNECTION_REQUEST_XML = get_sample("connect_connection_request.xml") +TEST_CONNECT_CONNECTION_REQUEST_TRAITS = { "base:operations": False, "base:special": True, } @@ -89,5 +91,5 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ALTER_CONNECTION_SUCCESS_LOG = get_sample("alter_connection_success.log") -TEST_ALTER_CONNECTION_ERROR_LOG = get_sample("alter_connection_error.log") +TEST_CONNECT_CONNECTION_SUCCESS_LOG = get_sample("connect_connection_success.log") +TEST_CONNECT_CONNECTION_ERROR_LOG = get_sample("connect_connection_error.log") diff --git a/tests/connection/test_connection_debug_logging.py b/tests/connection/test_connection_debug_logging.py index 5588d41d..7fd94a08 100644 --- a/tests/connection/test_connection_debug_logging.py +++ b/tests/connection/test_connection_debug_logging.py @@ -26,43 +26,43 @@ class TestConnectionDebugLogging(unittest.TestCase): # ============================================================================ # Alter Connection # ============================================================================ - def test_alter_connection_request_debug_log_works_on_success( + def test_connect_connection_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.connection_admin.alter( + self.connection_admin.connect( "ESWIFT", "TESTGRP0", - traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + traits=TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_TRAITS, ), success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestConnectionConstants.TEST_ALTER_CONNECTION_SUCCESS_LOG + success_log, TestConnectionConstants.TEST_CONNECT_CONNECTION_SUCCESS_LOG ) - def test_alter_connection_request_debug_log_works_on_error( + def test_connect_connection_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_ERROR_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.connection_admin.alter( + self.connection_admin.connect( "ESWIFT", "TESTGRP0", - traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + traits=TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_TRAITS, ), except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestConnectionConstants.TEST_ALTER_CONNECTION_ERROR_LOG + error_log, TestConnectionConstants.TEST_CONNECT_CONNECTION_ERROR_LOG ) diff --git a/tests/connection/test_connection_request_builder.py b/tests/connection/test_connection_request_builder.py index 141670a5..3667acd1 100644 --- a/tests/connection/test_connection_request_builder.py +++ b/tests/connection/test_connection_request_builder.py @@ -18,14 +18,14 @@ class TestConnectionRequestBuilder(unittest.TestCase): IRRSMO00.__init__ = Mock(return_value=None) connection_admin = ConnectionAdmin(generate_requests_only=True) - def test_connection_admin_build_alter_connection_request(self): - result = self.connection_admin.alter( + def test_connection_admin_build_connect_connection_request(self): + result = self.connection_admin.connect( "ESWIFT", "TESTGRP0", - traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + traits=TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_TRAITS, ) self.assertEqual( - result, TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_XML + result, TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_XML ) def test_connection_admin_build_delete_connection_request(self): diff --git a/tests/connection/test_connection_result_parser.py b/tests/connection/test_connection_result_parser.py index 1e6e3893..1a99f1c3 100644 --- a/tests/connection/test_connection_result_parser.py +++ b/tests/connection/test_connection_result_parser.py @@ -22,39 +22,39 @@ class TestConnectionResultParser(unittest.TestCase): # ============================================================================ # Alter Connection # ============================================================================ - def test_connection_admin_can_parse_alter_connection_success_xml( + def test_connection_admin_can_parse_connect_connection_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML ) self.assertEqual( - self.connection_admin.alter( + self.connection_admin.connect( "ESWIFT", "TESTGRP0", - traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + traits=TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_TRAITS, ), - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_SUCCESS_DICTIONARY, + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_SUCCESS_DICTIONARY, ) # Error in environment, TESTGRP0 group already deleted/not added - def test_connection_admin_can_parse_alter_connection_error_xml( + def test_connection_admin_can_parse_connect_connection_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_ERROR_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_ERROR_XML ) with self.assertRaises(SecurityRequestError) as exception: - self.connection_admin.alter( + self.connection_admin.connect( "ESWIFT", "TESTGRP0", - traits=TestConnectionConstants.TEST_ALTER_CONNECTION_REQUEST_TRAITS, + traits=TestConnectionConstants.TEST_CONNECT_CONNECTION_REQUEST_TRAITS, ) self.assertEqual( exception.exception.result, - TestConnectionConstants.TEST_ALTER_CONNECTION_RESULT_ERROR_DICTIONARY, + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/setropts/test_setropts_setters.py b/tests/setropts/test_setropts_setters.py index a85de899..14e7d7b6 100644 --- a/tests/setropts/test_setropts_setters.py +++ b/tests/setropts/test_setropts_setters.py @@ -22,52 +22,52 @@ class TestSetroptsSetters(unittest.TestCase): # Class adders # ============================================================================ def test_setropts_admin_build_add_audit_class_request(self): - result = self.setropts_admin.add_audit_class("elijtest") + result = self.setropts_admin.add_audit_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_AUDIT_CLASS_XML ) def test_setropts_admin_build_add_active_class_request(self): - result = self.setropts_admin.add_active_class("elijtest") + result = self.setropts_admin.add_active_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_ACTIVE_CLASS_XML ) def test_setropts_admin_build_add_statistics_class_request(self): - result = self.setropts_admin.add_statistics_class("elijtest") + result = self.setropts_admin.add_statistics_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_STATISTICS_CLASS_XML ) def test_setropts_admin_build_add_generic_command_processing_class_request(self): - result = self.setropts_admin.add_generic_command_processing_class("elijtest") + result = self.setropts_admin.add_generic_command_processing_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_COMMAND_PROCESSING_CLASS_XML, ) def test_setropts_admin_build_add_generic_profile_checking_class_request(self): - result = self.setropts_admin.add_generic_profile_checking_class("elijtest") + result = self.setropts_admin.add_generic_profile_checking_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_CHECKING_CLASS_XML, ) def test_setropts_admin_build_add_generic_profile_sharing_class_request(self): - result = self.setropts_admin.add_generic_profile_sharing_class("elijtest") + result = self.setropts_admin.add_generic_profile_sharing_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_SHARING_CLASS_XML, ) def test_setropts_admin_build_add_global_access_class_request(self): - result = self.setropts_admin.add_global_access_class("elijtest") + result = self.setropts_admin.add_global_access_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_GLOBAL_ACCESS_CLASS_XML ) def test_setropts_admin_build_add_raclist_class_request(self): - result = self.setropts_admin.add_raclist_class("elijtest") + result = self.setropts_admin.add_raclist_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_ADD_RACLIST_CLASS_XML ) @@ -76,52 +76,54 @@ def test_setropts_admin_build_add_raclist_class_request(self): # Class removers # ============================================================================ def test_setropts_admin_build_remove_audit_class_request(self): - result = self.setropts_admin.remove_audit_class("elijtest") + result = self.setropts_admin.remove_audit_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_AUDIT_CLASS_XML ) def test_setropts_admin_build_remove_active_class_request(self): - result = self.setropts_admin.remove_active_class("elijtest") + result = self.setropts_admin.remove_active_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_ACTIVE_CLASS_XML ) def test_setropts_admin_build_remove_statistics_class_request(self): - result = self.setropts_admin.remove_statistics_class("elijtest") + result = self.setropts_admin.remove_statistics_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_STATISTICS_CLASS_XML ) def test_setropts_admin_build_remove_generic_command_processing_class_request(self): - result = self.setropts_admin.remove_generic_command_processing_class("elijtest") + result = self.setropts_admin.remove_generic_command_processing_classes( + "elijtest" + ) self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_COMMAND_PROCESSING_CLASS_XML, ) def test_setropts_admin_build_remove_generic_profile_checking_class_request(self): - result = self.setropts_admin.remove_generic_profile_checking_class("elijtest") + result = self.setropts_admin.remove_generic_profile_checking_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_CHECKING_CLASS_XML, ) def test_setropts_admin_build_remove_generic_profile_sharing_class_request(self): - result = self.setropts_admin.remove_generic_profile_sharing_class("elijtest") + result = self.setropts_admin.remove_generic_profile_sharing_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_SHARING_CLASS_XML, ) def test_setropts_admin_build_remove_global_access_class_request(self): - result = self.setropts_admin.remove_global_access_class("elijtest") + result = self.setropts_admin.remove_global_access_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GLOBAL_ACCESS_CLASS_XML ) def test_setropts_admin_build_remove_raclist_class_request(self): - result = self.setropts_admin.remove_raclist_class("elijtest") + result = self.setropts_admin.remove_raclist_classes("elijtest") self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_RACLIST_CLASS_XML ) diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 55641af3..ac9bc6b3 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -129,6 +129,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD[ "base:passphrase" ] = "PassPhrasesAreCool!" +TEST_ADD_USER_REQUEST_INVALID_TRAITS = dict(TEST_ADD_USER_REQUEST_TRAITS) +TEST_ADD_USER_REQUEST_INVALID_TRAITS["omvs:invalid_trait"] = "TESTING VALUE" # Alter User TEST_ALTER_USER_REQUEST_XML = get_sample("alter_user_request.xml") diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index ba997e4e..f4d83698 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -6,7 +6,7 @@ import __init__ import tests.user.test_user_constants as TestUserConstants -from pyracf import UserAdmin +from pyracf import InvalidSegmentNameError, InvalidSegmentTraitError, UserAdmin from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -111,3 +111,36 @@ def test_user_admin_build_alter_request_update_existing_segment_traits(self): result, TestUserConstants.TEST_ALTER_USER_REQUEST_UPDATE_SEGMENTS_XML, ) + + # ============================================================================ + # Request Builder Errors + # ============================================================================ + def test_user_admin_build_add_request_with_invalid_segment_traits(self): + invalid_trait = "omvs:invalid_trait" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(InvalidSegmentTraitError) as exception: + user_admin.add( + "squidwrd", TestUserConstants.TEST_ADD_USER_REQUEST_INVALID_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Building of Security Request failed.\n\n" + + "Could not find " + + f"'{invalid_trait}' in valid segment traits for the requested operation.\n", + ) + + def test_user_admin_build_extract_request_with_invalid_segment_name(self): + invalid_segment = "test_segment" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(InvalidSegmentNameError) as exception: + user_admin.extract("squidwrd", {invalid_segment: True}) + self.assertEqual( + exception.exception.message, + "Building of Security Request failed.\n\n" + + "Could not find " + + f"'{invalid_segment}' in valid segments for the requested operation.\n", + ) From ee2df759da9610e469bd84eaaa1484633977b36f Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 25 Oct 2023 18:35:45 -0400 Subject: [PATCH 40/72] Added Extract to Add Function -Used preliminary extract to determine if add is valid (in user) -Updated unit testing framework to account for this -Moved checking of redacted secrets and debug logging to alter (for User) due to Add changes Signed-off-by: Elijah Swift --- pyracf/__init__.py | 1 + pyracf/common/add_operation_error.py | 24 ++ pyracf/common/logger.py | 2 +- pyracf/common/security_admin.py | 16 +- pyracf/common/security_request_error.py | 12 + pyracf/setropts/setropts_admin.py | 2 +- pyracf/user/user_admin.py | 25 +- ...tract_group_result_base_only_success.json} | 0 ...xtract_group_result_base_only_success.xml} | 0 tests/group/test_group_constants.py | 8 +- tests/group/test_group_getters.py | 16 +- tests/group/test_group_result_parser.py | 10 +- tests/user/test_user_constants.py | 151 +++++---- tests/user/test_user_debug_logging.py | 210 ++++++++----- tests/user/test_user_getters.py | 8 +- tests/user/test_user_request_builder.py | 6 +- tests/user/test_user_result_parser.py | 177 ++++++----- ...add_user_additional_secret_added_error.log | 120 ------- ...d_user_additional_secret_added_success.log | 120 ------- .../user/user_log_samples/add_user_error.log | 120 ------- ...add_user_passphrase_and_password_error.log | 130 -------- ...d_user_passphrase_and_password_success.log | 130 -------- .../add_user_passphrase_error.log | 125 -------- .../add_user_passphrase_success.log | 125 -------- .../add_user_password_error.log | 125 -------- .../add_user_password_success.log | 125 -------- .../user_log_samples/add_user_success.log | 120 ------- ...ter_user_additional_secret_added_error.log | 283 +++++++++++++++++ ...r_user_additional_secret_added_success.log | 275 ++++++++++++++++ .../user_log_samples/alter_user_error.log | 283 +++++++++++++++++ ...ter_user_passphrase_and_password_error.log | 293 ++++++++++++++++++ ...r_user_passphrase_and_password_success.log | 285 +++++++++++++++++ .../alter_user_passphrase_error.log | 288 +++++++++++++++++ .../alter_user_passphrase_success.log | 280 +++++++++++++++++ .../alter_user_password_error.log | 288 +++++++++++++++++ .../alter_user_password_success.log | 280 +++++++++++++++++ .../user_log_samples/alter_user_success.log | 260 ++++++++++++++++ .../add_user_result_error.json | 31 +- .../add_user_result_error.xml | 27 +- .../alter_user_result_error.json | 32 +- .../alter_user_result_error.xml | 24 +- .../alter_user_result_extended_success.xml | 14 + ...result_passphrase_and_password_error.json} | 15 +- ..._result_passphrase_and_password_error.xml} | 13 +- ...sult_passphrase_and_password_success.json} | 12 +- ...esult_passphrase_and_password_success.xml} | 8 +- ...> alter_user_result_passphrase_error.json} | 15 +- ...=> alter_user_result_passphrase_error.xml} | 13 +- ...alter_user_result_passphrase_success.json} | 12 +- ... alter_user_result_passphrase_success.xml} | 8 +- ... => alter_user_result_password_error.json} | 15 +- ...l => alter_user_result_password_error.xml} | 13 +- ...> alter_user_result_password_success.json} | 12 +- ...=> alter_user_result_password_success.xml} | 8 +- .../extract_user_result_base_only_error.json | 22 ++ .../extract_user_result_base_only_error.xml | 14 + ...xtract_user_result_base_only_success.json} | 2 +- ...extract_user_result_base_only_success.xml} | 4 +- .../extract_user_result_invattr_error.json | 19 ++ .../extract_user_result_invattr_error.xml | 15 + 60 files changed, 3421 insertions(+), 1650 deletions(-) create mode 100644 pyracf/common/add_operation_error.py rename tests/group/group_result_samples/{extract_group_result_base_only_no_omvs_success.json => extract_group_result_base_only_success.json} (100%) rename tests/group/group_result_samples/{extract_group_result_base_only_no_omvs_success.xml => extract_group_result_base_only_success.xml} (100%) delete mode 100644 tests/user/user_log_samples/add_user_additional_secret_added_error.log delete mode 100644 tests/user/user_log_samples/add_user_additional_secret_added_success.log delete mode 100644 tests/user/user_log_samples/add_user_error.log delete mode 100644 tests/user/user_log_samples/add_user_passphrase_and_password_error.log delete mode 100644 tests/user/user_log_samples/add_user_passphrase_and_password_success.log delete mode 100644 tests/user/user_log_samples/add_user_passphrase_error.log delete mode 100644 tests/user/user_log_samples/add_user_passphrase_success.log delete mode 100644 tests/user/user_log_samples/add_user_password_error.log delete mode 100644 tests/user/user_log_samples/add_user_password_success.log delete mode 100644 tests/user/user_log_samples/add_user_success.log create mode 100644 tests/user/user_log_samples/alter_user_additional_secret_added_error.log create mode 100644 tests/user/user_log_samples/alter_user_additional_secret_added_success.log create mode 100644 tests/user/user_log_samples/alter_user_error.log create mode 100644 tests/user/user_log_samples/alter_user_passphrase_and_password_error.log create mode 100644 tests/user/user_log_samples/alter_user_passphrase_and_password_success.log create mode 100644 tests/user/user_log_samples/alter_user_passphrase_error.log create mode 100644 tests/user/user_log_samples/alter_user_passphrase_success.log create mode 100644 tests/user/user_log_samples/alter_user_password_error.log create mode 100644 tests/user/user_log_samples/alter_user_password_success.log create mode 100644 tests/user/user_log_samples/alter_user_success.log create mode 100644 tests/user/user_result_samples/alter_user_result_extended_success.xml rename tests/user/user_result_samples/{add_user_result_passphrase_and_password_error.json => alter_user_result_passphrase_and_password_error.json} (56%) rename tests/user/user_result_samples/{add_user_result_passphrase_and_password_error.xml => alter_user_result_passphrase_and_password_error.xml} (57%) rename tests/user/user_result_samples/{add_user_result_passphrase_and_password_success.json => alter_user_result_passphrase_and_password_success.json} (68%) rename tests/user/user_result_samples/{add_user_result_passphrase_and_password_success.xml => alter_user_result_passphrase_and_password_success.xml} (72%) rename tests/user/user_result_samples/{add_user_result_passphrase_error.json => alter_user_result_passphrase_error.json} (57%) rename tests/user/user_result_samples/{add_user_result_passphrase_error.xml => alter_user_result_passphrase_error.xml} (58%) rename tests/user/user_result_samples/{add_user_result_passphrase_success.json => alter_user_result_passphrase_success.json} (67%) rename tests/user/user_result_samples/{add_user_result_passphrase_success.xml => alter_user_result_passphrase_success.xml} (71%) rename tests/user/user_result_samples/{add_user_result_password_error.json => alter_user_result_password_error.json} (57%) rename tests/user/user_result_samples/{add_user_result_password_error.xml => alter_user_result_password_error.xml} (59%) rename tests/user/user_result_samples/{add_user_result_password_success.json => alter_user_result_password_success.json} (67%) rename tests/user/user_result_samples/{add_user_result_password_success.xml => alter_user_result_password_success.xml} (71%) create mode 100644 tests/user/user_result_samples/extract_user_result_base_only_error.json create mode 100644 tests/user/user_result_samples/extract_user_result_base_only_error.xml rename tests/user/user_result_samples/{extract_user_result_base_only_no_omvs_success.json => extract_user_result_base_only_success.json} (96%) rename tests/user/user_result_samples/{extract_user_result_base_only_no_omvs_success.xml => extract_user_result_base_only_success.xml} (92%) create mode 100644 tests/user/user_result_samples/extract_user_result_invattr_error.json create mode 100644 tests/user/user_result_samples/extract_user_result_invattr_error.xml diff --git a/pyracf/__init__.py b/pyracf/__init__.py index 44409d47..7c686b12 100644 --- a/pyracf/__init__.py +++ b/pyracf/__init__.py @@ -1,5 +1,6 @@ """Make security admin subclasses available from package root.""" from .access.access_admin import AccessAdmin +from .common.add_operation_error import AddOperationError from .common.alter_operation_error import AlterOperationError from .common.invalid_segment_name_error import InvalidSegmentNameError from .common.invalid_segment_trait_error import InvalidSegmentTraitError diff --git a/pyracf/common/add_operation_error.py b/pyracf/common/add_operation_error.py new file mode 100644 index 00000000..57d7db15 --- /dev/null +++ b/pyracf/common/add_operation_error.py @@ -0,0 +1,24 @@ +"""Exception to use when Add operation would alter an existing profile.""" + + +class AddOperationError(Exception): + """ + Raised when a profile passed into an Add is successfully extracted. + """ + + def __init__(self, profile_name: str, class_name: str) -> None: + self.message = "Security request made to IRRSMO00 failed." + admin_types = ["USER", "GROUP", "DATASET"] + if class_name not in admin_types: + self.message += ( + "\n\nTarget profile " + + f"'{profile_name}' already exists as a profile in the {class_name} class." + ) + else: + self.message += ( + "\n\nTarget profile " + + f"'{profile_name}' already exists as a {class_name} profile." + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/common/logger.py b/pyracf/common/logger.py index ed1f3dc8..07a491ae 100644 --- a/pyracf/common/logger.py +++ b/pyracf/common/logger.py @@ -166,7 +166,7 @@ def redact_result_xml( match = re.search(rf"{racf_key.upper()} +\(", xml_string) if not match: continue - xml_string = self.__redact_string(xml_string, match.end(), ") ") + xml_string = self.__redact_string(xml_string, match.end(), ")") return xml_string def __colorize_json(self, json_text: str) -> str: diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 677de6d3..bc47eeb0 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -70,7 +70,7 @@ def __init__( self.__preserved_segment_traits = {} self._trait_map = {} self.__debug = debug - self.__generate_requests_only = generate_requests_only + self._generate_requests_only = generate_requests_only if update_existing_segment_traits is not None: self.__update_valid_segment_traits(update_existing_segment_traits) if replace_existing_segment_traits is not None: @@ -123,7 +123,7 @@ def _extract_and_check_result( ) -> dict: """Extract a RACF profile.""" result = self._make_request(security_request) - if self.__generate_requests_only: + if self._generate_requests_only: return result self._format_profile(result) if self.__debug: @@ -155,7 +155,7 @@ def _make_request( security_request.dump_request_xml(encoding="utf-8"), secret_traits=self.__secret_traits, ) - if self.__generate_requests_only: + if self._generate_requests_only: request_xml = self.__logger.redact_request_xml( security_request.dump_request_xml(encoding="utf-8"), secret_traits=self.__secret_traits, @@ -202,7 +202,7 @@ def _to_steps(self, results: Union[List[dict], dict, bytes]) -> Union[dict, byte """ if isinstance(results, dict) or isinstance(results, bytes): results = [results] - if self.__generate_requests_only: + if self._generate_requests_only: concatenated_xml = b"" for request_xml in results: if request_xml: @@ -320,8 +320,8 @@ def _get_profile( self, result: Union[dict, bytes], index: int = 0 ) -> Union[dict, bytes]: """Extract the profile section from a result dictionary.""" - if self.__generate_requests_only: - # Allows this function to work with "self.__generate_requests_only" mode. + if self._generate_requests_only: + # Allows this function to work with "self._generate_requests_only" mode. return result return result["securityResult"][self.__profile_type]["commands"][0]["profiles"][ index @@ -331,8 +331,8 @@ def _get_field( self, profile: Union[dict, bytes], segment: str, field: str ) -> Union[bytes, Any, None]: """Extract the value of a field from a segment in a profile.""" - if self.__generate_requests_only: - # Allows this function to work with "self.__generate_requests_only" mode. + if self._generate_requests_only: + # Allows this function to work with "self._generate_requests_only" mode. return profile try: return profile[segment][field] diff --git a/pyracf/common/security_request_error.py b/pyracf/common/security_request_error.py index d197a48b..97e61b7a 100644 --- a/pyracf/common/security_request_error.py +++ b/pyracf/common/security_request_error.py @@ -17,3 +17,15 @@ def __init__(self, result: dict) -> None: def __str__(self) -> str: return self.message + + def scan_for_error(self, security_definition_tag: str, error_id: str): + commands = self.result["securityResult"][security_definition_tag].get( + "commands" + ) + if not isinstance(commands, list): + return False + messages = commands[0].get("messages", []) + if error_id in "".join(messages): + return True + else: + return False diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 677fefe7..bbcc17d2 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -136,7 +136,7 @@ def get_class_attributes(self, class_name: str) -> Union[list, bytes]: """Get RACF get attributes.""" profile = self.list_racf_options(options_only=True) if not isinstance(profile, dict): - # Allows this function to work with "self.__generate_requests_only" mode. + # Allows this function to work with "self._generate_requests_only" mode. return profile return [ class_type diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 2860a817..f29c8aec 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -2,6 +2,7 @@ from typing import List, Union +from pyracf.common.add_operation_error import AddOperationError from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin from pyracf.common.security_request_error import SecurityRequestError @@ -399,13 +400,29 @@ def set_omvs_program( # ============================================================================ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new user.""" - self._build_segment_dictionaries(traits) - user_request = UserRequest(userid, "set") - self._build_xml_segments(user_request) - return self._make_request(user_request) + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + user_request = UserRequest(userid, "set") + self._build_xml_segments(user_request) + return self._make_request(user_request) + try: + self.extract(userid) + except SecurityRequestError as exception: + if not exception.scan_for_error("user", "ICH30001I"): + raise exception + self._build_segment_dictionaries(traits) + user_request = UserRequest(userid, "set") + self._build_xml_segments(user_request) + return self._make_request(user_request) + raise AddOperationError(userid, "USER") def alter(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: """Alter an existing user.""" + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + user_request = UserRequest(userid, "set") + self._build_xml_segments(user_request, alter=True) + return self._make_request(user_request, irrsmo00_precheck=True) try: self.extract(userid) except SecurityRequestError: diff --git a/tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.json b/tests/group/group_result_samples/extract_group_result_base_only_success.json similarity index 100% rename from tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.json rename to tests/group/group_result_samples/extract_group_result_base_only_success.json diff --git a/tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.xml b/tests/group/group_result_samples/extract_group_result_base_only_success.xml similarity index 100% rename from tests/group/group_result_samples/extract_group_result_base_only_no_omvs_success.xml rename to tests/group/group_result_samples/extract_group_result_base_only_success.xml diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index 671ba3fc..9da4f7d6 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -42,11 +42,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_DICTIONARY = get_sample( "extract_group_result_base_omvs_error.json" ) -TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML = get_sample( - "extract_group_result_base_only_no_omvs_success.xml" +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_group_result_base_only_success.xml" ) -TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON = get_sample( - "extract_group_result_base_only_no_omvs_success.json" +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_JSON = get_sample( + "extract_group_result_base_only_success.json" ) # Delete Group diff --git a/tests/group/test_group_getters.py b/tests/group/test_group_getters.py index a8e42493..25177201 100644 --- a/tests/group/test_group_getters.py +++ b/tests/group/test_group_getters.py @@ -27,7 +27,7 @@ def test_group_admin_has_group_special_authority_returns_true_when_group_special call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertTrue( self.group_admin.has_group_special_authority("TESTGRP0", "ESWIFT") @@ -63,7 +63,7 @@ def test_group_admin_has_group_operations_authority_returns_true_when_group_oper call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertTrue( self.group_admin.has_group_operations_authority("TESTGRP0", "LEONARD") @@ -99,7 +99,7 @@ def test_group_admin_has_group_auditor_authority_returns_true_when_group_auditor call_racf_mock: Mock, ): group_extract_auditor = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) group_extract_auditor = group_extract_auditor.replace( " CONNECT ATTRIBUTES=SPECIAL", @@ -115,7 +115,7 @@ def test_group_admin_has_group_auditor_authority_returns_false_when_not_group_au call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertFalse( self.group_admin.has_group_auditor_authority("TESTGRP0", "ESWIFT") @@ -140,7 +140,7 @@ def test_group_admin_has_group_access_attribute_returns_true_when_grpacc( call_racf_mock: Mock, ): group_extract_grpacc = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) group_extract_grpacc = group_extract_grpacc.replace( " CONNECT ATTRIBUTES=OPERATIONS", @@ -156,7 +156,7 @@ def test_group_admin_has_group_access_attribute_returns_false_when_not_grpacc( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertFalse( self.group_admin.has_group_access_attribute("TESTGRP0", "LEONARD") @@ -201,7 +201,7 @@ def test_group_admin_get_omvs_gid_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.group_admin.get_omvs_gid("TESTGRP0")) @@ -237,6 +237,6 @@ def test_group_admin_get_ovm_gid_returns_none_when_no_ovm_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.group_admin.get_ovm_gid("TESTGRP0")) diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 650ed110..5762beb7 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -59,7 +59,7 @@ def test_group_admin_can_parse_alter_group_success_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, ] self.assertEqual( @@ -96,7 +96,7 @@ def test_group_admin_can_parse_alter_group_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -124,16 +124,16 @@ def test_group_admin_can_parse_extract_group_base_omvs_success_xml( TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) - def test_group_admin_can_parse_extract_group_base_only_no_omvs_success_xml( + def test_group_admin_can_parse_extract_group_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.group_admin.extract("TESTGRP0"), - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_JSON, ) # Error in environment, TESTGRP0 already deleted/not added diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index ac9bc6b3..8819cc92 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -20,48 +20,51 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ADD_USER_RESULT_SUCCESS_DICTIONARY = get_sample("add_user_result_success.json") TEST_ADD_USER_RESULT_ERROR_XML = get_sample("add_user_result_error.xml") TEST_ADD_USER_RESULT_ERROR_DICTIONARY = get_sample("add_user_result_error.json") -TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_XML = get_sample( - "add_user_result_password_success.xml" + +# Alter User +TEST_ALTER_USER_RESULT_SUCCESS_XML = get_sample("alter_user_result_success.xml") +TEST_ALTER_USER_RESULT_SUCCESS_DICTIONARY = get_sample("alter_user_result_success.json") +TEST_ALTER_USER_RESULT_ERROR_XML = get_sample("alter_user_result_error.xml") +TEST_ALTER_USER_RESULT_ERROR_DICTIONARY = get_sample("alter_user_result_error.json") +TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_XML = get_sample( + "alter_user_result_password_success.xml" ) -TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY = get_sample( - "add_user_result_password_success.json" +TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY = get_sample( + "alter_user_result_password_success.json" ) -TEST_ADD_USER_PASSWORD_RESULT_ERROR_XML = get_sample( - "add_user_result_password_error.xml" +TEST_ALTER_USER_PASSWORD_RESULT_ERROR_XML = get_sample( + "alter_user_result_password_error.xml" ) -TEST_ADD_USER_PASSWORD_RESULT_ERROR_DICTIONARY = get_sample( - "add_user_result_password_error.json" +TEST_ALTER_USER_PASSWORD_RESULT_ERROR_DICTIONARY = get_sample( + "alter_user_result_password_error.json" ) -TEST_ADD_USER_PASSPHRASE_RESULT_SUCCESS_XML = get_sample( - "add_user_result_passphrase_success.xml" +TEST_ALTER_USER_PASSPHRASE_RESULT_SUCCESS_XML = get_sample( + "alter_user_result_passphrase_success.xml" ) -TEST_ADD_USER_PASSPHRASE_RESULT_SUCCESS_DICTIONARY = get_sample( - "add_user_result_passphrase_success.json" +TEST_ALTER_USER_PASSPHRASE_RESULT_SUCCESS_DICTIONARY = get_sample( + "alter_user_result_passphrase_success.json" ) -TEST_ADD_USER_PASSPHRASE_RESULT_ERROR_XML = get_sample( - "add_user_result_passphrase_error.xml" +TEST_ALTER_USER_PASSPHRASE_RESULT_ERROR_XML = get_sample( + "alter_user_result_passphrase_error.xml" ) -TEST_ADD_USER_PASSPHRASE_RESULT_ERROR_DICTIONARY = get_sample( - "add_user_result_passphrase_error.json" +TEST_ALTER_USER_PASSPHRASE_RESULT_ERROR_DICTIONARY = get_sample( + "alter_user_result_passphrase_error.json" ) -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML = get_sample( - "add_user_result_passphrase_and_password_success.xml" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML = get_sample( + "alter_user_result_passphrase_and_password_success.xml" ) -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_DICTIONARY = get_sample( - "add_user_result_passphrase_and_password_success.json" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_DICTIONARY = get_sample( + "alter_user_result_passphrase_and_password_success.json" ) -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML = get_sample( - "add_user_result_passphrase_and_password_error.xml" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML = get_sample( + "alter_user_result_passphrase_and_password_error.xml" ) -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_DICTIONARY = get_sample( - "add_user_result_passphrase_and_password_error.json" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_DICTIONARY = get_sample( + "alter_user_result_passphrase_and_password_error.json" +) +TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_XML = get_sample( + "alter_user_result_extended_success.xml" ) - -# Alter User -TEST_ALTER_USER_RESULT_SUCCESS_XML = get_sample("alter_user_result_success.xml") -TEST_ALTER_USER_RESULT_SUCCESS_DICTIONARY = get_sample("alter_user_result_success.json") -TEST_ALTER_USER_RESULT_ERROR_XML = get_sample("alter_user_result_error.xml") -TEST_ALTER_USER_RESULT_ERROR_DICTIONARY = get_sample("alter_user_result_error.json") # Extract User TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML = get_sample( @@ -76,11 +79,17 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_DICTIONARY = get_sample( "extract_user_result_base_omvs_error.json" ) -TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML = get_sample( - "extract_user_result_base_only_no_omvs_success.xml" +TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_user_result_base_only_success.xml" +) +TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON = get_sample( + "extract_user_result_base_only_success.json" ) -TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON = get_sample( - "extract_user_result_base_only_no_omvs_success.json" +TEST_EXTRACT_USER_RESULT_BASE_ONLY_ERROR_XML = get_sample( + "extract_user_result_base_only_error.xml" +) +TEST_EXTRACT_USER_RESULT_BASE_ONLY_ERROR_JSON = get_sample( + "extract_user_result_base_only_error.json" ) TEST_EXTRACT_USER_RESULT_WITH_CLASS_AUTHORIZATIONS = get_sample( "extract_user_result_with_class_authorizations.xml" @@ -88,6 +97,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample( "extract_user_result_with_command_audit_trail.xml" ) +TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_XML = get_sample( + "extract_user_result_invattr_error.xml" +) +TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_JSON = get_sample( + "extract_user_result_invattr_error.json" +) # Delete User TEST_DELETE_USER_RESULT_SUCCESS_XML = get_sample("delete_user_result_success.xml") @@ -116,19 +131,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "omvs:home": "/u/squidwrd", "omvs:program": "/bin/sh", } -TEST_ADD_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ADD_USER_REQUEST_TRAITS) -TEST_ADD_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF" -TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE = dict(TEST_ADD_USER_REQUEST_TRAITS) -TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE["base:password"] = "PASSWORD" -TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE = dict(TEST_ADD_USER_REQUEST_TRAITS) -TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE["base:passphrase"] = "PassPhrasesAreCool!" -TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD = dict( - TEST_ADD_USER_REQUEST_TRAITS -) -TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD["base:password"] = "GIyTTqdF" -TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD[ - "base:passphrase" -] = "PassPhrasesAreCool!" TEST_ADD_USER_REQUEST_INVALID_TRAITS = dict(TEST_ADD_USER_REQUEST_TRAITS) TEST_ADD_USER_REQUEST_INVALID_TRAITS["omvs:invalid_trait"] = "TESTING VALUE" @@ -139,6 +141,33 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "omvs:home": "/u/clarinet", "omvs:program": False, } +TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED = { + "base:name": "Squidward", + "base:owner": "leonard", + "base:special": True, + "omvs:uid": "2424", + "omvs:home": "/u/squidwrd", + "omvs:program": "/bin/sh", +} +TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED) +TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF" +TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE = dict( + TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED +) +TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE["base:password"] = "PASSWORD" +TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE = dict( + TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED +) +TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE["base:passphrase"] = "PassPhrasesAreCool!" +TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD = dict( + TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED +) +TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD["base:password"] = "GIyTTqdF" +TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD[ + "base:passphrase" +] = "PassPhrasesAreCool!" +TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR = dict(TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED) +TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR["omvs:uid"] = 90000000000 # Extract User TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML = get_sample( @@ -198,27 +227,27 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_USER_SUCCESS_LOG = get_sample("add_user_success.log") -TEST_ADD_USER_ERROR_LOG = get_sample("add_user_error.log") +TEST_ALTER_USER_SUCCESS_LOG = get_sample("alter_user_success.log") +TEST_ALTER_USER_ERROR_LOG = get_sample("alter_user_error.log") -TEST_ADD_USER_ADDITIONAL_SECRET_ADDED_SUCCESS_LOG = get_sample( - "add_user_additional_secret_added_success.log" +TEST_ALTER_USER_ADDITIONAL_SECRET_ADDED_SUCCESS_LOG = get_sample( + "alter_user_additional_secret_added_success.log" ) -TEST_ADD_USER_ADDITIONAL_SECRET_ADDED_ERROR_LOG = get_sample( - "add_user_additional_secret_added_error.log" +TEST_ALTER_USER_ADDITIONAL_SECRET_ADDED_ERROR_LOG = get_sample( + "alter_user_additional_secret_added_error.log" ) -TEST_ADD_USER_PASSWORD_SUCCESS_LOG = get_sample("add_user_password_success.log") -TEST_ADD_USER_PASSWORD_ERROR_LOG = get_sample("add_user_password_error.log") +TEST_ALTER_USER_PASSWORD_SUCCESS_LOG = get_sample("alter_user_password_success.log") +TEST_ALTER_USER_PASSWORD_ERROR_LOG = get_sample("alter_user_password_error.log") -TEST_ADD_USER_PASSPHRASE_SUCCESS_LOG = get_sample("add_user_passphrase_success.log") -TEST_ADD_USER_PASSPHRASE_ERROR_LOG = get_sample("add_user_passphrase_error.log") +TEST_ALTER_USER_PASSPHRASE_SUCCESS_LOG = get_sample("alter_user_passphrase_success.log") +TEST_ALTER_USER_PASSPHRASE_ERROR_LOG = get_sample("alter_user_passphrase_error.log") -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_SUCCESS_LOG = get_sample( - "add_user_passphrase_and_password_success.log" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_SUCCESS_LOG = get_sample( + "alter_user_passphrase_and_password_success.log" ) -TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_ERROR_LOG = get_sample( - "add_user_passphrase_and_password_error.log" +TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_ERROR_LOG = get_sample( + "alter_user_passphrase_and_password_error.log" ) TEST_EXTRACT_USER_BASE_OMVS_SUCCESS_LOG = get_sample( diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index 615959fa..c845a9c2 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -27,252 +27,304 @@ class TestUserDebugLogging(unittest.TestCase): simple_password = "PASSWORD" # ============================================================================ - # Add User + # Alter User # ============================================================================ - def test_add_user_request_debug_log_works_on_success( + def test_alter_user_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(success_log, TestUserConstants.TEST_ADD_USER_SUCCESS_LOG) + self.assertEqual(success_log, TestUserConstants.TEST_ALTER_USER_SUCCESS_LOG) - def test_add_user_request_debug_log_works_on_error( + def test_alter_user_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestUserConstants.TEST_ADD_USER_ERROR_LOG) + self.assertEqual(error_log, TestUserConstants.TEST_ALTER_USER_ERROR_LOG) # ============================================================================ # Secrets Redaction # ============================================================================ - def test_add_user_request_debug_log_passwords_get_redacted_on_success( + def test_alter_user_request_debug_log_passwords_get_redacted_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestUserConstants.TEST_ADD_USER_PASSWORD_SUCCESS_LOG + success_log, TestUserConstants.TEST_ALTER_USER_PASSWORD_SUCCESS_LOG ) self.assertNotIn(self.test_password, success_log) - def test_add_user_request_debug_log_passwords_get_redacted_on_error( + def test_alter_user_request_debug_log_passwords_get_redacted_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD, + traits=error_traits, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestUserConstants.TEST_ADD_USER_PASSWORD_ERROR_LOG) + self.assertEqual( + error_log, TestUserConstants.TEST_ALTER_USER_PASSWORD_ERROR_LOG + ) self.assertNotIn(self.test_password, error_log) - def test_add_user_request_debug_log_passphrases_get_redacted_on_success( + def test_alter_user_request_debug_log_passphrases_get_redacted_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestUserConstants.TEST_ADD_USER_PASSPHRASE_SUCCESS_LOG + success_log, TestUserConstants.TEST_ALTER_USER_PASSPHRASE_SUCCESS_LOG ) self.assertNotIn(self.test_passphrase, success_log) - def test_add_user_request_debug_log_passphrases_get_redacted_on_error( + def test_alter_user_request_debug_log_passphrases_get_redacted_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE, + traits=error_traits, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestUserConstants.TEST_ADD_USER_PASSPHRASE_ERROR_LOG + error_log, TestUserConstants.TEST_ALTER_USER_PASSPHRASE_ERROR_LOG ) self.assertNotIn(self.test_passphrase, error_log) - def test_add_user_request_debug_log_passphrases_and_passwords_get_redacted_on_success( + def test_alter_user_request_debug_log_passphrases_and_passwords_get_redacted_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( success_log, - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_SUCCESS_LOG, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_SUCCESS_LOG, ) self.assertNotIn(self.test_passphrase, success_log) self.assertNotIn(self.test_password, success_log) - def test_add_user_request_debug_log_passphrases_and_passwords_get_redacted_on_error( + def test_alter_user_request_debug_log_passphrases_and_passwords_get_redacted_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, + traits=error_traits, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_ERROR_LOG + error_log, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_ERROR_LOG, ) self.assertNotIn(self.test_passphrase, error_log) self.assertNotIn(self.test_password, error_log) - def test_add_user_request_debug_log_password_xml_tags_not_redacted_on_success( + def test_alter_user_request_debug_log_password_xml_tags_not_redacted_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.user_admin.add( + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestUserConstants.TEST_ADD_USER_PASSWORD_SUCCESS_LOG + success_log, TestUserConstants.TEST_ALTER_USER_PASSWORD_SUCCESS_LOG ) self.assertEqual(success_log.count("********"), 4) self.assertIn(self.simple_password, success_log) - def test_add_user_request_debug_log_password_xml_tags_not_redacted_on_error( + def test_alter_user_request_debug_log_password_xml_tags_not_redacted_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( + "squidwrd", + traits=error_traits, + ) + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestUserConstants.TEST_ADD_USER_PASSWORD_ERROR_LOG) + self.assertEqual( + error_log, TestUserConstants.TEST_ALTER_USER_PASSWORD_ERROR_LOG + ) self.assertEqual(error_log.count("********"), 4) self.assertIn(self.simple_password, error_log) # ============================================================================ # Add Additional Secrets # ============================================================================ - def test_add_user_request_debug_log_additional_secret_added_get_redacted_on_success( + def test_alter_user_request_debug_log_additional_secret_added_get_redacted_on_success( self, call_racf_mock: Mock, ): user_admin = UserAdmin(debug=True, additional_secret_traits=["omvs:uid"]) - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - user_admin.add( + user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( success_log, - TestUserConstants.TEST_ADD_USER_ADDITIONAL_SECRET_ADDED_SUCCESS_LOG, + TestUserConstants.TEST_ALTER_USER_ADDITIONAL_SECRET_ADDED_SUCCESS_LOG, ) self.assertNotIn( - TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS["omvs:uid"], success_log + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED["omvs:uid"], + success_log, ) - def test_add_user_request_debug_log_additional_secret_added_get_redacted_on_error( + def test_alter_user_request_debug_log_additional_secret_added_get_redacted_on_error( self, call_racf_mock: Mock, ): user_admin = UserAdmin(debug=True, additional_secret_traits=["omvs:uid"]) - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - user_admin.add( + user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestUserConstants.TEST_ADD_USER_ADDITIONAL_SECRET_ADDED_ERROR_LOG + error_log, + TestUserConstants.TEST_ALTER_USER_ADDITIONAL_SECRET_ADDED_ERROR_LOG, ) self.assertNotIn( - TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS["omvs:uid"], error_log + "(" + + str( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR["omvs:uid"] + ) + + ")", + error_log, ) # ============================================================================ diff --git a/tests/user/test_user_getters.py b/tests/user/test_user_getters.py index 089a43bf..a3c54ba1 100644 --- a/tests/user/test_user_getters.py +++ b/tests/user/test_user_getters.py @@ -151,7 +151,7 @@ def test_user_admin_get_class_authorizations_returns_empty_list_when_no_class_au call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual(self.user_admin.get_class_authorizations("squidwrd"), []) @@ -192,7 +192,7 @@ def test_user_admin_get_omvs_uid_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.user_admin.get_omvs_uid("squidwrd")) @@ -223,7 +223,7 @@ def test_user_admin_get_omvs_home_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.user_admin.get_omvs_home("squidwrd")) @@ -254,6 +254,6 @@ def test_user_admin_get_omvs_program_returns_none_when_no_omvs_segment_exists( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertIsNone(self.user_admin.get_omvs_program("squidwrd")) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index f4d83698..7722f80f 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -55,7 +55,7 @@ def test_user_admin_build_add_user_request_password_redacted( ): result = self.user_admin.add( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD, ) self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_PASSWORD_XML) self.assertNotIn(self.test_password, result.decode("utf-8")) @@ -65,7 +65,7 @@ def test_user_admin_build_add_user_request_passphrase_redacted( ): result = self.user_admin.add( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE, ) self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_PASSPHRASE_XML) self.assertNotIn(self.test_passphrase, result.decode("utf-8")) @@ -75,7 +75,7 @@ def test_user_admin_build_add_user_request_passphrase_and_password_redacted( ): result = self.user_admin.add( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, ) self.assertEqual( result, TestUserConstants.TEST_ADD_USER_REQUEST_PASSPHRASE_AND_PASSWORD_XML diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 64c9f83e..36ce90ac 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -29,7 +29,10 @@ def test_user_admin_can_parse_add_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_ERROR_XML, + TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML, + ] self.assertEqual( self.user_admin.add( "squidwrd", @@ -38,20 +41,23 @@ def test_user_admin_can_parse_add_user_success_xml( TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_DICTIONARY, ) - # Error in environment, SQUIDWRD already added/exists + # Error in command, SQUIDWARD is invalid USERID def test_user_admin_can_parse_add_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_XML, + TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.user_admin.add( - "squidwrd", + "squidward", traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS, ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ADD_USER_RESULT_ERROR_DICTIONARY, + TestUserConstants.TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_JSON, ) # ============================================================================ @@ -62,7 +68,7 @@ def test_user_admin_can_parse_alter_user_success_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, ] self.assertEqual( @@ -79,7 +85,7 @@ def test_user_admin_throws_error_on_alter_new_user( profile_name = "squidwrd" admin_name = "USER" call_racf_mock.side_effect = [ - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_ERROR_XML, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_ERROR_XML, TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, ] with self.assertRaises(AlterOperationError) as exception: @@ -93,18 +99,19 @@ def test_user_admin_throws_error_on_alter_new_user( + f"'{profile_name}' does not exist as a {admin_name} profile.", ) - # Error: invalid parameter "name" + # Error: invalid uid '90000000000' def test_user_admin_can_parse_alter_user_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: self.user_admin.alter( - "squidwrd", traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS + "squidwrd", + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR, ) self.assertEqual( exception.exception.result, @@ -126,16 +133,16 @@ def test_user_admin_can_parse_extract_user_base_omvs_success_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) - def test_user_admin_can_parse_extract_user_base_only_no_omvs_success_xml( + def test_user_admin_can_parse_extract_user_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_XML + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.user_admin.extract("squidwrd", segments={"omvs": True}), - TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_NO_OMVS_SUCCESS_JSON, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON, ) # Error in environment, SQUIDWRD already deleted/not added @@ -168,100 +175,113 @@ def test_user_admin_can_parse_extract_user_and_ignore_command_audit_trail_xml( # ============================================================================ # Password and Password Phrase Redaction # ============================================================================ - def test_user_admin_password_redacted_add_user_success_xml( + def test_user_admin_password_redacted_alter_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_XML - ) - result = self.user_admin.add( + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_XML, + ] + result = self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD, ) self.assertEqual( result, - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY, ) result_str = str(result) self.assertNotIn(self.test_password, result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - # Error in environment, SQUIDWRD already added/exists - def test_user_admin_password_redacted_add_user_error_xml( + # Error: invalid uid '90000000000' + def test_user_admin_password_redacted_alter_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD, + traits=error_traits, ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_DICTIONARY, ) result_str = str(exception.exception.result) self.assertNotIn(self.test_password, result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - def test_user_admin_passphrase_redacted_add_user_success_xml( + def test_user_admin_passphrase_redacted_alter_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_SUCCESS_XML - ) - result = self.user_admin.add( + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_SUCCESS_XML, + ] + result = self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE, ) self.assertEqual( result, - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_SUCCESS_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_SUCCESS_DICTIONARY, ) result_str = str(result) self.assertNotIn(self.test_passphrase, result_str) self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) - # Error in environment, SQUIDWRD already added/exists - def test_user_admin_passphrase_redacted_add_user_error_xml( + # Error: invalid uid '90000000000' + def test_user_admin_passphrase_redacted_alter_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE, + traits=error_traits, ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ADD_USER_PASSPHRASE_RESULT_ERROR_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_RESULT_ERROR_DICTIONARY, ) result_str = str(exception.exception.result) self.assertNotIn(self.test_passphrase, result_str) self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) - def test_user_admin_passphrase_and_password_redacted_add_user_success_xml( + def test_user_admin_passphrase_and_password_redacted_alter_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML - ) - result = self.user_admin.add( + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_XML, + ] + result = self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, ) self.assertEqual( result, - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_SUCCESS_DICTIONARY, ) result_str = str(result) self.assertNotIn(self.test_passphrase, result_str) @@ -269,22 +289,27 @@ def test_user_admin_passphrase_and_password_redacted_add_user_success_xml( self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - # Error in environment, SQUIDWRD already added/exists - def test_user_admin_passphrase_and_password_redacted_add_user_error_xml( + # Error: invalid uid '90000000000' + def test_user_admin_passphrase_and_password_redacted_alter_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSPHRASE_AND_PASSWORD, + traits=error_traits, ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ADD_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSPHRASE_AND_PASSWORD_RESULT_ERROR_DICTIONARY, ) result_str = str(exception.exception.result) self.assertNotIn(self.test_passphrase, result_str) @@ -292,42 +317,48 @@ def test_user_admin_passphrase_and_password_redacted_add_user_error_xml( self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - def test_user_admin_password_message_not_redacted_add_user_success_xml( + def test_user_admin_password_message_not_redacted_alter_user_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_XML - ) - result = self.user_admin.add( + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_XML, + ] + result = self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, ) self.assertEqual( result, - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_SUCCESS_DICTIONARY, ) result_str = str(result) self.assertNotIn("(" + self.simple_password + ")", result_str) self.assertNotIn("(" + " " * len(self.simple_password) + ")", result_str) self.assertIn(self.simple_password, result_str) - # Error in environment, SQUIDWRD already added/exists - def test_user_admin_password_message_not_redacted_add_user_error_xml( + # Error: invalid uid '90000000000' + def test_user_admin_password_message_not_redacted_alter_user_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: - self.user_admin.add( + error_traits = dict( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, + traits=error_traits, ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ADD_USER_PASSWORD_RESULT_ERROR_DICTIONARY, + TestUserConstants.TEST_ALTER_USER_PASSWORD_RESULT_ERROR_DICTIONARY, ) result_str = str(exception.exception.result) self.assertNotIn("(" + self.simple_password + ")", result_str) diff --git a/tests/user/user_log_samples/add_user_additional_secret_added_error.log b/tests/user/user_log_samples/add_user_additional_secret_added_error.log deleted file mode 100644 index d8f8dc5a..00000000 --- a/tests/user/user_log_samples/add_user_additional_secret_added_error.log +++ /dev/null @@ -1,120 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "********", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - - - ******** - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (********) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (********) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_additional_secret_added_success.log b/tests/user/user_log_samples/add_user_additional_secret_added_success.log deleted file mode 100644 index 2ad712e4..00000000 --- a/tests/user/user_log_samples/add_user_additional_secret_added_success.log +++ /dev/null @@ -1,120 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "********", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - - - ******** - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (********) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (********) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_error.log b/tests/user/user_log_samples/add_user_error.log deleted file mode 100644 index e5bba4fe..00000000 --- a/tests/user/user_log_samples/add_user_error.log +++ /dev/null @@ -1,120 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_passphrase_and_password_error.log b/tests/user/user_log_samples/add_user_passphrase_and_password_error.log deleted file mode 100644 index c30b9aba..00000000 --- a/tests/user/user_log_samples/add_user_passphrase_and_password_error.log +++ /dev/null @@ -1,130 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:password": { - "value": "********", - "operation": null - }, - "base:passphrase": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_passphrase_and_password_success.log b/tests/user/user_log_samples/add_user_passphrase_and_password_success.log deleted file mode 100644 index dd17d227..00000000 --- a/tests/user/user_log_samples/add_user_passphrase_and_password_success.log +++ /dev/null @@ -1,130 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:password": { - "value": "********", - "operation": null - }, - "base:passphrase": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_passphrase_error.log b/tests/user/user_log_samples/add_user_passphrase_error.log deleted file mode 100644 index e3b19e12..00000000 --- a/tests/user/user_log_samples/add_user_passphrase_error.log +++ /dev/null @@ -1,125 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:passphrase": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_passphrase_success.log b/tests/user/user_log_samples/add_user_passphrase_success.log deleted file mode 100644 index 426485c2..00000000 --- a/tests/user/user_log_samples/add_user_passphrase_success.log +++ /dev/null @@ -1,125 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:passphrase": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_password_error.log b/tests/user/user_log_samples/add_user_password_error.log deleted file mode 100644 index 4bf641d2..00000000 --- a/tests/user/user_log_samples/add_user_password_error.log +++ /dev/null @@ -1,125 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:password": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_password_success.log b/tests/user/user_log_samples/add_user_password_success.log deleted file mode 100644 index ad25b298..00000000 --- a/tests/user/user_log_samples/add_user_password_success.log +++ /dev/null @@ -1,125 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - }, - "base:password": { - "value": "********", - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - ******** - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/add_user_success.log b/tests/user/user_log_samples/add_user_success.log deleted file mode 100644 index e462fb22..00000000 --- a/tests/user/user_log_samples/add_user_success.log +++ /dev/null @@ -1,120 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - UserAdmin.add() - - -{ - "base": { - "base:name": { - "value": "Squidward", - "operation": null - }, - "base:owner": { - "value": "leonard", - "operation": null - }, - "base:special": { - "value": true, - "operation": null - } - }, - "omvs": { - "omvs:uid": { - "value": "2424", - "operation": null - }, - "omvs:home": { - "value": "/u/squidwrd", - "operation": null - }, - "omvs:program": { - "value": "/bin/sh", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - UserAdmin.add() - - - - - - Squidward - leonard - - - - 2424 - /u/squidwrd - /bin/sh - - - - - - [pyRACF:Debug] - Result XML - UserAdmin.add() - - - - - - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - UserAdmin.add() - - -{ - "securityResult": { - "user": { - "name": "SQUIDWRD", - "operation": "set", - "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/user/user_log_samples/alter_user_additional_secret_added_error.log b/tests/user/user_log_samples/alter_user_additional_secret_added_error.log new file mode 100644 index 00000000..92d3947b --- /dev/null +++ b/tests/user/user_log_samples/alter_user_additional_secret_added_error.log @@ -0,0 +1,283 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": "********", + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + + + ******** + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********)) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_additional_secret_added_success.log b/tests/user/user_log_samples/alter_user_additional_secret_added_success.log new file mode 100644 index 00000000..214ac28c --- /dev/null +++ b/tests/user/user_log_samples/alter_user_additional_secret_added_success.log @@ -0,0 +1,275 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": "********", + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + + + ******** + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********)) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_error.log b/tests/user/user_log_samples/alter_user_error.log new file mode 100644 index 00000000..93552625 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_error.log @@ -0,0 +1,283 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": 90000000000, + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + + + 90000000000 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (90000000000)) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (90000000000))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log b/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log new file mode 100644 index 00000000..48120c67 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log @@ -0,0 +1,293 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:password": { + "value": "********", + "operation": null + }, + "base:passphrase": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": 90000000000, + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + ******** + + + 90000000000 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log b/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log new file mode 100644 index 00000000..e5a0401a --- /dev/null +++ b/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log @@ -0,0 +1,285 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:password": { + "value": "********", + "operation": null + }, + "base:passphrase": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": "2424", + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + ******** + + + 2424 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_passphrase_error.log b/tests/user/user_log_samples/alter_user_passphrase_error.log new file mode 100644 index 00000000..7ad51915 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_passphrase_error.log @@ -0,0 +1,288 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:passphrase": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": 90000000000, + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + + + 90000000000 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_passphrase_success.log b/tests/user/user_log_samples/alter_user_passphrase_success.log new file mode 100644 index 00000000..a92acc47 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_passphrase_success.log @@ -0,0 +1,280 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:passphrase": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": "2424", + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + + + 2424 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_password_error.log b/tests/user/user_log_samples/alter_user_password_error.log new file mode 100644 index 00000000..918d0466 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_password_error.log @@ -0,0 +1,288 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:password": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": 90000000000, + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + + + 90000000000 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_password_success.log b/tests/user/user_log_samples/alter_user_password_success.log new file mode 100644 index 00000000..384b8293 --- /dev/null +++ b/tests/user/user_log_samples/alter_user_password_success.log @@ -0,0 +1,280 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:name": { + "value": "Squidward", + "operation": null + }, + "base:owner": { + "value": "leonard", + "operation": null + }, + "base:special": { + "value": true, + "operation": null + }, + "base:password": { + "value": "********", + "operation": null + } + }, + "omvs": { + "omvs:uid": { + "value": "2424", + "operation": null + }, + "omvs:home": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:program": { + "value": "/bin/sh", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + Squidward + leonard + + ******** + + + 2424 + /u/squidwrd + /bin/sh + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_log_samples/alter_user_success.log b/tests/user/user_log_samples/alter_user_success.log new file mode 100644 index 00000000..ac9f17af --- /dev/null +++ b/tests/user/user_log_samples/alter_user_success.log @@ -0,0 +1,260 @@ + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094", + " DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A", + " ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LAST-ACCESS=23.094/12:55:37", + " CLASS AUTHORIZATIONS=NONE", + " NO-INSTALLATION-DATA", + " NO-MODEL-NAME", + " LOGON ALLOWED (DAYS) (TIME)", + " ---------------------------------------------", + " ANYDAY ANYTIME", + " GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094", + " CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN", + " CONNECT ATTRIBUTES=NONE", + " REVOKE DATE=NONE RESUME DATE=NONE", + "SECURITY-LEVEL=NONE SPECIFIED", + "CATEGORY-AUTHORIZATION", + " NONE SPECIFIED", + "SECURITY-LABEL=NONE SPECIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": "unknown", + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + UserAdmin.alter() + + +{ + "base": { + "base:special": { + "value": false, + "operation": "delete" + } + }, + "omvs": { + "omvs:home": { + "value": "/u/clarinet", + "operation": null + }, + "omvs:program": { + "value": false, + "operation": "delete" + } + } +} + + + [pyRACF:Debug] + Request XML + UserAdmin.alter() + + + + + + + + + /u/clarinet + + + + + + + [pyRACF:Debug] + Result XML + UserAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM ) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + UserAdmin.alter() + + +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM )" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/user/user_result_samples/add_user_result_error.json b/tests/user/user_result_samples/add_user_result_error.json index 3e054d37..543c008a 100644 --- a/tests/user/user_result_samples/add_user_result_error.json +++ b/tests/user/user_result_samples/add_user_result_error.json @@ -1,28 +1,19 @@ { "securityResult": { "user": { - "name": "SQUIDWRD", + "name": "squidward", "operation": "set", "requestId": "UserRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" - } - ] + "error": { + "errorFunction": 10, + "errorCode": 2000, + "errorReason": 68, + "errorMessage": "Invalid attribute value specified.", + "errorOffset": 149, + "textInError": "name" + } }, - "returnCode": 4, - "reasonCode": 0 + "returnCode": 2000, + "reasonCode": 68 } } \ No newline at end of file diff --git a/tests/user/user_result_samples/add_user_result_error.xml b/tests/user/user_result_samples/add_user_result_error.xml index 17fcd3c6..42675813 100644 --- a/tests/user/user_result_samples/add_user_result_error.xml +++ b/tests/user/user_result_samples/add_user_result_error.xml @@ -1,20 +1,15 @@ - - - 8 - 16 - 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) - + + + 10 + 2000 + 68 + Invalid attribute value specified. + 149 + name + - 4 - 0 + 2000 + 68 \ No newline at end of file diff --git a/tests/user/user_result_samples/alter_user_result_error.json b/tests/user/user_result_samples/alter_user_result_error.json index 543c008a..e387aea5 100644 --- a/tests/user/user_result_samples/alter_user_result_error.json +++ b/tests/user/user_result_samples/alter_user_result_error.json @@ -1,19 +1,27 @@ { "securityResult": { "user": { - "name": "squidward", + "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", - "error": { - "errorFunction": 10, - "errorCode": 2000, - "errorReason": 68, - "errorMessage": "Invalid attribute value specified.", - "errorOffset": 149, - "textInError": "name" - } + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (90000000000))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] }, - "returnCode": 2000, - "reasonCode": 68 + "returnCode": 4, + "reasonCode": 0 } -} \ No newline at end of file +} diff --git a/tests/user/user_result_samples/alter_user_result_error.xml b/tests/user/user_result_samples/alter_user_result_error.xml index 42675813..8a62f076 100644 --- a/tests/user/user_result_samples/alter_user_result_error.xml +++ b/tests/user/user_result_samples/alter_user_result_error.xml @@ -1,15 +1,17 @@ - - - 10 - 2000 - 68 - Invalid attribute value specified. - 149 - name - + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (90000000000)) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS + - 2000 - 68 + 4 + 0 \ No newline at end of file diff --git a/tests/user/user_result_samples/alter_user_result_extended_success.xml b/tests/user/user_result_samples/alter_user_result_extended_success.xml new file mode 100644 index 00000000..87293679 --- /dev/null +++ b/tests/user/user_result_samples/alter_user_result_extended_success.xml @@ -0,0 +1,14 @@ + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (2424)) + + + 0 + 0 + \ No newline at end of file diff --git a/tests/user/user_result_samples/add_user_result_passphrase_and_password_error.json b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.json similarity index 56% rename from tests/user/user_result_samples/add_user_result_passphrase_and_password_error.json rename to tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.json index b9ba8b26..d937bb8e 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_and_password_error.json +++ b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.json @@ -4,21 +4,20 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ { "safReturnCode": 8, "returnCode": 16, "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" } ] }, diff --git a/tests/user/user_result_samples/add_user_result_passphrase_and_password_error.xml b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.xml similarity index 57% rename from tests/user/user_result_samples/add_user_result_passphrase_and_password_error.xml rename to tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.xml index 0754c474..ae8f287f 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_and_password_error.xml +++ b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_error.xml @@ -1,18 +1,15 @@ + Definition exists. Add command skipped due to precheck option 8 16 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD ( ) PHRASE ( ) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD ( ) PHRASE ( ) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS 4 diff --git a/tests/user/user_result_samples/add_user_result_passphrase_and_password_success.json b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.json similarity index 68% rename from tests/user/user_result_samples/add_user_result_passphrase_and_password_success.json rename to tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.json index 2272e108..bdbb9d44 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_and_password_success.json +++ b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.json @@ -4,16 +4,10 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, { "safReturnCode": 0, "returnCode": 0, diff --git a/tests/user/user_result_samples/add_user_result_passphrase_and_password_success.xml b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.xml similarity index 72% rename from tests/user/user_result_samples/add_user_result_passphrase_and_password_success.xml rename to tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.xml index 8a502749..58b50bf9 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_and_password_success.xml +++ b/tests/user/user_result_samples/alter_user_result_passphrase_and_password_success.xml @@ -1,13 +1,7 @@ - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - + Definition exists. Add command skipped due to precheck option 0 0 diff --git a/tests/user/user_result_samples/add_user_result_passphrase_error.json b/tests/user/user_result_samples/alter_user_result_passphrase_error.json similarity index 57% rename from tests/user/user_result_samples/add_user_result_passphrase_error.json rename to tests/user/user_result_samples/alter_user_result_passphrase_error.json index 7e0a60df..5b067f5c 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_error.json +++ b/tests/user/user_result_samples/alter_user_result_passphrase_error.json @@ -4,21 +4,20 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ { "safReturnCode": 8, "returnCode": 16, "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" } ] }, diff --git a/tests/user/user_result_samples/add_user_result_passphrase_error.xml b/tests/user/user_result_samples/alter_user_result_passphrase_error.xml similarity index 58% rename from tests/user/user_result_samples/add_user_result_passphrase_error.xml rename to tests/user/user_result_samples/alter_user_result_passphrase_error.xml index 7155fc95..98edd9d7 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_error.xml +++ b/tests/user/user_result_samples/alter_user_result_passphrase_error.xml @@ -1,18 +1,15 @@ + Definition exists. Add command skipped due to precheck option 8 16 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE ( ) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PHRASE ( ) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS 4 diff --git a/tests/user/user_result_samples/add_user_result_passphrase_success.json b/tests/user/user_result_samples/alter_user_result_passphrase_success.json similarity index 67% rename from tests/user/user_result_samples/add_user_result_passphrase_success.json rename to tests/user/user_result_samples/alter_user_result_passphrase_success.json index a3da3294..153669eb 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_success.json +++ b/tests/user/user_result_samples/alter_user_result_passphrase_success.json @@ -4,16 +4,10 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, { "safReturnCode": 0, "returnCode": 0, diff --git a/tests/user/user_result_samples/add_user_result_passphrase_success.xml b/tests/user/user_result_samples/alter_user_result_passphrase_success.xml similarity index 71% rename from tests/user/user_result_samples/add_user_result_passphrase_success.xml rename to tests/user/user_result_samples/alter_user_result_passphrase_success.xml index 1796a3a6..99696d89 100644 --- a/tests/user/user_result_samples/add_user_result_passphrase_success.xml +++ b/tests/user/user_result_samples/alter_user_result_passphrase_success.xml @@ -1,13 +1,7 @@ - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - + Definition exists. Add command skipped due to precheck option 0 0 diff --git a/tests/user/user_result_samples/add_user_result_password_error.json b/tests/user/user_result_samples/alter_user_result_password_error.json similarity index 57% rename from tests/user/user_result_samples/add_user_result_password_error.json rename to tests/user/user_result_samples/alter_user_result_password_error.json index c85706b0..b2792339 100644 --- a/tests/user/user_result_samples/add_user_result_password_error.json +++ b/tests/user/user_result_samples/alter_user_result_password_error.json @@ -4,21 +4,20 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ { "safReturnCode": 8, "returnCode": 16, "reasonCode": 8, - "image": "ADDUSER SQUIDWRD ", + "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))", "messages": [ - "IKJ56702I INVALID USERID, SQUIDWRD" + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD (********) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh'))" } ] }, diff --git a/tests/user/user_result_samples/add_user_result_password_error.xml b/tests/user/user_result_samples/alter_user_result_password_error.xml similarity index 59% rename from tests/user/user_result_samples/add_user_result_password_error.xml rename to tests/user/user_result_samples/alter_user_result_password_error.xml index 94046b54..8827d971 100644 --- a/tests/user/user_result_samples/add_user_result_password_error.xml +++ b/tests/user/user_result_samples/alter_user_result_password_error.xml @@ -1,18 +1,15 @@ + Definition exists. Add command skipped due to precheck option 8 16 8 - ADDUSER SQUIDWRD - IKJ56702I INVALID USERID, SQUIDWRD - - - 0 - 0 - 0 - ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD ( ) OMVS (UID (2424) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + ALTUSER SQUIDWRD NAME ('Squidward') OWNER (leonard) SPECIAL PASSWORD ( ) OMVS (UID (90000000000) HOME ('/u/squidwrd') PROGRAM ('/bin/sh')) + IKJ56702I INVALID UID, 90000000000 + IKJ56701I MISSING OMVS UID+ + IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS 4 diff --git a/tests/user/user_result_samples/add_user_result_password_success.json b/tests/user/user_result_samples/alter_user_result_password_success.json similarity index 67% rename from tests/user/user_result_samples/add_user_result_password_success.json rename to tests/user/user_result_samples/alter_user_result_password_success.json index 0ba9cd36..44dcb6a3 100644 --- a/tests/user/user_result_samples/add_user_result_password_success.json +++ b/tests/user/user_result_samples/alter_user_result_password_success.json @@ -4,16 +4,10 @@ "name": "SQUIDWRD", "operation": "set", "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDUSER SQUIDWRD ", - "messages": [ - "ICH01024I User SQUIDWRD is defined as PROTECTED." - ] - }, { "safReturnCode": 0, "returnCode": 0, diff --git a/tests/user/user_result_samples/add_user_result_password_success.xml b/tests/user/user_result_samples/alter_user_result_password_success.xml similarity index 71% rename from tests/user/user_result_samples/add_user_result_password_success.xml rename to tests/user/user_result_samples/alter_user_result_password_success.xml index 5f85509a..85d01eb2 100644 --- a/tests/user/user_result_samples/add_user_result_password_success.xml +++ b/tests/user/user_result_samples/alter_user_result_password_success.xml @@ -1,13 +1,7 @@ - - 0 - 0 - 0 - ADDUSER SQUIDWRD - ICH01024I User SQUIDWRD is defined as PROTECTED. - + Definition exists. Add command skipped due to precheck option 0 0 diff --git a/tests/user/user_result_samples/extract_user_result_base_only_error.json b/tests/user/user_result_samples/extract_user_result_base_only_error.json new file mode 100644 index 00000000..7edd69fd --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_base_only_error.json @@ -0,0 +1,22 @@ +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 4, + "image": "LISTUSER SQUIDWRD ", + "messages": [ + "ICH30001I UNABLE TO LOCATE USER ENTRY SQUIDWRD" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_base_only_error.xml b/tests/user/user_result_samples/extract_user_result_base_only_error.xml new file mode 100644 index 00000000..bf9d9089 --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_base_only_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + LISTUSER SQUIDWRD + ICH30001I UNABLE TO LOCATE USER ENTRY SQUIDWRD + + + 4 + 0 + \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.json b/tests/user/user_result_samples/extract_user_result_base_only_success.json similarity index 96% rename from tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.json rename to tests/user/user_result_samples/extract_user_result_base_only_success.json index b6af8ec6..15fdda78 100644 --- a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.json +++ b/tests/user/user_result_samples/extract_user_result_base_only_success.json @@ -9,7 +9,7 @@ "safReturnCode": 0, "returnCode": 0, "reasonCode": 0, - "image": "LISTUSER SQUIDWRD OMVS ", + "image": "LISTUSER SQUIDWRD ", "profiles": [ { "base": { diff --git a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.xml b/tests/user/user_result_samples/extract_user_result_base_only_success.xml similarity index 92% rename from tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.xml rename to tests/user/user_result_samples/extract_user_result_base_only_success.xml index cc34292c..61a46535 100644 --- a/tests/user/user_result_samples/extract_user_result_base_only_no_omvs_success.xml +++ b/tests/user/user_result_samples/extract_user_result_base_only_success.xml @@ -5,7 +5,7 @@ 0 0 0 - LISTUSER SQUIDWRD OMVS + LISTUSER SQUIDWRD USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A ATTRIBUTES=NONE @@ -25,8 +25,6 @@ CATEGORY-AUTHORIZATION NONE SPECIFIED SECURITY-LABEL=NONE SPECIFIED - - NO OMVS INFORMATION 0 diff --git a/tests/user/user_result_samples/extract_user_result_invattr_error.json b/tests/user/user_result_samples/extract_user_result_invattr_error.json new file mode 100644 index 00000000..c15ae7cf --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_invattr_error.json @@ -0,0 +1,19 @@ +{ + "securityResult": { + "user": { + "name": "squidward", + "operation": "listdata", + "requestId": "UserRequest", + "error": { + "errorFunction": 10, + "errorCode": 2000, + "errorReason": 68, + "errorMessage": "Invalid attribute value specified.", + "errorOffset": 149, + "textInError": "name" + } + }, + "returnCode": 2000, + "reasonCode": 68 + } +} \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_invattr_error.xml b/tests/user/user_result_samples/extract_user_result_invattr_error.xml new file mode 100644 index 00000000..fc284509 --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_invattr_error.xml @@ -0,0 +1,15 @@ + + + + + 10 + 2000 + 68 + Invalid attribute value specified. + 149 + name + + + 2000 + 68 + \ No newline at end of file From ea0577f92951095ae6b8bb314bf0c8a9a4c0f785 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 25 Oct 2023 19:29:54 -0400 Subject: [PATCH 41/72] Pull Dev Changes Pull Dev Changes and Fix resulting conflicts Signed-off-by: Elijah Swift --- pyracf/setropts/setropts_admin.py | 12 ++++++++---- tests/user/test_user_constants.py | 15 ++++++++++----- .../alter_user_additional_secret_added_error.log | 6 +++--- ...alter_user_additional_secret_added_success.log | 6 +++--- tests/user/user_log_samples/alter_user_error.log | 6 +++--- .../alter_user_passphrase_and_password_error.log | 6 +++--- ...alter_user_passphrase_and_password_success.log | 6 +++--- .../alter_user_passphrase_error.log | 6 +++--- .../alter_user_passphrase_success.log | 6 +++--- .../alter_user_password_error.log | 6 +++--- .../alter_user_password_success.log | 6 +++--- .../user/user_log_samples/alter_user_success.log | 6 +++--- ...ract_user_result_invalid_attribute_error.json} | 0 ...tract_user_result_invalid_attribute_error.xml} | 0 14 files changed, 48 insertions(+), 39 deletions(-) rename tests/user/user_result_samples/{extract_user_result_invattr_error.json => extract_user_result_invalid_attribute_error.json} (100%) rename tests/user/user_result_samples/{extract_user_result_invattr_error.xml => extract_user_result_invalid_attribute_error.xml} (100%) diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 063b4a2f..d3043a65 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -132,7 +132,7 @@ def refresh_raclist(self, class_names: Union[List[str], str]) -> Union[dict, byt # ============================================================================ # Get attributes # ============================================================================ - def get_classes_attributes(self, class_name: str) -> Union[list, bytes]: + def get_class_attributes(self, class_name: str) -> Union[list, bytes]: """Get RACF get attributes.""" profile = self.list_racf_options(options_only=True) if not isinstance(profile, dict): @@ -159,7 +159,7 @@ def remove_audit_classes( ) -> Union[dict, bytes]: """Remove class(es) from the list of classes that RACF performs auditing for.""" result = self.alter(options={"delete:base:audit_classes": class_names}) - + return self._to_steps(result) # ============================================================================ # Active Classes @@ -220,7 +220,9 @@ def remove_generic_command_processing_classes( Remove class(es) from the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"delete:base:general_command_classes": class_names}) + result = self.alter( + options={"delete:base:general_command_classes": class_names} + ) return self._to_steps(result) # ============================================================================ @@ -254,7 +256,9 @@ def add_generic_profile_sharing_classes( Add class(es) to the list of classes that are eligible for general resource profile sharing in common storage. """ - result = self.alter(options={"base:generic_profile_sharing_classes": class_names}) + result = self.alter( + options={"base:generic_profile_sharing_classes": class_names} + ) return self._to_steps(result) def remove_generic_profile_sharing_classes( diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 70fc2bd2..fedc6e55 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -98,10 +98,16 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "extract_user_result_with_command_audit_trail.xml" ) TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_XML = get_sample( - "extract_user_result_invattr_error.xml" + "extract_user_result_invalid_attribute_error.xml" ) TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_JSON = get_sample( - "extract_user_result_invattr_error.json" + "extract_user_result_invalid_attribute_error.json" +) +TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML = get_sample( + "extract_user_result_base_omvs_tso_revoke_resume.xml" +) +TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY = get_sample( + "extract_user_result_base_omvs_tso_revoke_resume.json" ) # Delete User @@ -170,7 +176,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_USER_REQUEST_XML = get_sample("alter_user_request.xml") TEST_ALTER_USER_REQUEST_TRAITS = { "base:special": False, - "base:operator": True, "omvs:home_directory": "/u/clarinet", "omvs:default_shell": False, } @@ -179,8 +184,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "base:owner": "leonard", "base:special": True, "omvs:uid": "2424", - "omvs:home": "/u/squidwrd", - "omvs:program": "/bin/sh", + "omvs:home_directory": "/u/squidwrd", + "omvs:default_shell": "/bin/sh", } TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED) TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF" diff --git a/tests/user/user_log_samples/alter_user_additional_secret_added_error.log b/tests/user/user_log_samples/alter_user_additional_secret_added_error.log index 92d3947b..4a3f324b 100644 --- a/tests/user/user_log_samples/alter_user_additional_secret_added_error.log +++ b/tests/user/user_log_samples/alter_user_additional_secret_added_error.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -191,11 +191,11 @@ "value": "********", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_additional_secret_added_success.log b/tests/user/user_log_samples/alter_user_additional_secret_added_success.log index 214ac28c..36746060 100644 --- a/tests/user/user_log_samples/alter_user_additional_secret_added_success.log +++ b/tests/user/user_log_samples/alter_user_additional_secret_added_success.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -191,11 +191,11 @@ "value": "********", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_error.log b/tests/user/user_log_samples/alter_user_error.log index 93552625..d73d98a3 100644 --- a/tests/user/user_log_samples/alter_user_error.log +++ b/tests/user/user_log_samples/alter_user_error.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -191,11 +191,11 @@ "value": 90000000000, "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log b/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log index 48120c67..bdab5be8 100644 --- a/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log +++ b/tests/user/user_log_samples/alter_user_passphrase_and_password_error.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -199,11 +199,11 @@ "value": 90000000000, "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log b/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log index e5a0401a..1f9589a3 100644 --- a/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log +++ b/tests/user/user_log_samples/alter_user_passphrase_and_password_success.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -199,11 +199,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_passphrase_error.log b/tests/user/user_log_samples/alter_user_passphrase_error.log index 7ad51915..21a29802 100644 --- a/tests/user/user_log_samples/alter_user_passphrase_error.log +++ b/tests/user/user_log_samples/alter_user_passphrase_error.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -195,11 +195,11 @@ "value": 90000000000, "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_passphrase_success.log b/tests/user/user_log_samples/alter_user_passphrase_success.log index a92acc47..036f42b0 100644 --- a/tests/user/user_log_samples/alter_user_passphrase_success.log +++ b/tests/user/user_log_samples/alter_user_passphrase_success.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -195,11 +195,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_password_error.log b/tests/user/user_log_samples/alter_user_password_error.log index 918d0466..ffc81d57 100644 --- a/tests/user/user_log_samples/alter_user_password_error.log +++ b/tests/user/user_log_samples/alter_user_password_error.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -195,11 +195,11 @@ "value": 90000000000, "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_password_success.log b/tests/user/user_log_samples/alter_user_password_success.log index 384b8293..5b51838c 100644 --- a/tests/user/user_log_samples/alter_user_password_success.log +++ b/tests/user/user_log_samples/alter_user_password_success.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -195,11 +195,11 @@ "value": "2424", "operation": null }, - "omvs:home": { + "omvs:home_directory": { "value": "/u/squidwrd", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": "/bin/sh", "operation": null } diff --git a/tests/user/user_log_samples/alter_user_success.log b/tests/user/user_log_samples/alter_user_success.log index ac9f17af..5cd64554 100644 --- a/tests/user/user_log_samples/alter_user_success.log +++ b/tests/user/user_log_samples/alter_user_success.log @@ -145,7 +145,7 @@ "connectDate": "4/4/2023", "connects": 0, "uacc": null, - "lastConnect": "unknown", + "lastConnect": null, "connectAttributes": [], "revokeDate": null, "resumeDate": null @@ -179,11 +179,11 @@ } }, "omvs": { - "omvs:home": { + "omvs:home_directory": { "value": "/u/clarinet", "operation": null }, - "omvs:program": { + "omvs:default_shell": { "value": false, "operation": "delete" } diff --git a/tests/user/user_result_samples/extract_user_result_invattr_error.json b/tests/user/user_result_samples/extract_user_result_invalid_attribute_error.json similarity index 100% rename from tests/user/user_result_samples/extract_user_result_invattr_error.json rename to tests/user/user_result_samples/extract_user_result_invalid_attribute_error.json diff --git a/tests/user/user_result_samples/extract_user_result_invattr_error.xml b/tests/user/user_result_samples/extract_user_result_invalid_attribute_error.xml similarity index 100% rename from tests/user/user_result_samples/extract_user_result_invattr_error.xml rename to tests/user/user_result_samples/extract_user_result_invalid_attribute_error.xml From 58e391b34a4857e87c675cd7d0e414baa295e51f Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 26 Oct 2023 10:41:54 -0400 Subject: [PATCH 42/72] Expand Setropts Unit Testing Add Unit Testing for list and string forms of multiple "classes" passed to Setropts Admin Settrs Signed-off-by: Elijah Swift --- .../setropts_add_active_classes.xml | 5 + .../setropts_add_audit_classes.xml | 5 + ...add_generic_command_processing_classes.xml | 5 + ...s_add_generic_profile_checking_classes.xml | 5 + ...ts_add_generic_profile_sharing_classes.xml | 5 + .../setropts_add_global_access_classes.xml | 5 + .../setropts_add_raclist_classes.xml | 5 + .../setropts_add_statistics_classes.xml | 5 + .../setropts_refresh_raclist_multiple.xml | 6 + .../setropts_remove_active_classes.xml | 5 + .../setropts_remove_audit_classes.xml | 5 + ...ove_generic_command_processing_classes.xml | 5 + ...emove_generic_profile_checking_classes.xml | 5 + ...remove_generic_profile_sharing_classes.xml | 5 + .../setropts_remove_global_access_classes.xml | 5 + .../setropts_remove_raclist_classes.xml | 5 + .../setropts_remove_statistics_classes.xml | 5 + tests/setropts/test_setropts_constants.py | 43 +++ tests/setropts/test_setropts_setters.py | 266 ++++++++++++++++++ 19 files changed, 395 insertions(+) create mode 100644 tests/setropts/setropts_request_samples/setropts_add_active_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_active_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_audit_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_generic_command_processing_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_generic_profile_checking_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_generic_profile_sharing_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_global_access_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_raclist_classes.xml create mode 100644 tests/setropts/setropts_request_samples/setropts_remove_statistics_classes.xml diff --git a/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml new file mode 100644 index 00000000..91b4edcc --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml new file mode 100644 index 00000000..7871f86b --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml new file mode 100644 index 00000000..4b6bea5c --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml new file mode 100644 index 00000000..fb4d71d5 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml new file mode 100644 index 00000000..9334ea6d --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml new file mode 100644 index 00000000..979d0f52 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml new file mode 100644 index 00000000..effd0461 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml new file mode 100644 index 00000000..0b24d2f4 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml b/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml new file mode 100644 index 00000000..a4b09c0e --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml @@ -0,0 +1,6 @@ + + + elijtest xfacilit + + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_active_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_active_classes.xml new file mode 100644 index 00000000..2a4bab27 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_active_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_audit_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_audit_classes.xml new file mode 100644 index 00000000..7d681bca --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_audit_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_generic_command_processing_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_generic_command_processing_classes.xml new file mode 100644 index 00000000..9cdc42b0 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_generic_command_processing_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_checking_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_checking_classes.xml new file mode 100644 index 00000000..d30197ae --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_checking_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_sharing_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_sharing_classes.xml new file mode 100644 index 00000000..18ddc428 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_generic_profile_sharing_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_global_access_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_global_access_classes.xml new file mode 100644 index 00000000..757a8261 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_global_access_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_raclist_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_raclist_classes.xml new file mode 100644 index 00000000..bc928274 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_raclist_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_remove_statistics_classes.xml b/tests/setropts/setropts_request_samples/setropts_remove_statistics_classes.xml new file mode 100644 index 00000000..6319c3f1 --- /dev/null +++ b/tests/setropts/setropts_request_samples/setropts_remove_statistics_classes.xml @@ -0,0 +1,5 @@ + + + elijtest xfacilit + + \ No newline at end of file diff --git a/tests/setropts/test_setropts_constants.py b/tests/setropts/test_setropts_constants.py index 0fc75f89..28184a13 100644 --- a/tests/setropts/test_setropts_constants.py +++ b/tests/setropts/test_setropts_constants.py @@ -92,6 +92,49 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_SETROPTS_ADD_RACLIST_CLASS_XML = get_sample("setropts_add_raclist_class.xml") TEST_SETROPTS_REMOVE_RACLIST_CLASS_XML = get_sample("setropts_remove_raclist_class.xml") TEST_SETROPTS_REFRESH_RACLIST_XML = get_sample("setropts_refresh_raclist.xml") +TEST_SETROPTS_ADD_AUDIT_CLASSES_XML = get_sample("setropts_add_audit_classes.xml") +TEST_SETROPTS_REMOVE_AUDIT_CLASSES_XML = get_sample("setropts_remove_audit_classes.xml") +TEST_SETROPTS_ADD_ACTIVE_CLASSES_XML = get_sample("setropts_add_active_classes.xml") +TEST_SETROPTS_REMOVE_ACTIVE_CLASSES_XML = get_sample( + "setropts_remove_active_classes.xml" +) +TEST_SETROPTS_ADD_STATISTICS_CLASSES_XML = get_sample( + "setropts_add_statistics_classes.xml" +) +TEST_SETROPTS_REMOVE_STATISTICS_CLASSES_XML = get_sample( + "setropts_remove_statistics_classes.xml" +) +TEST_SETROPTS_ADD_GENERIC_COMMAND_PROCESSING_CLASSES_XML = get_sample( + "setropts_add_generic_command_processing_classes.xml" +) +TEST_SETROPTS_REMOVE_GENERIC_COMMAND_PROCESSING_CLASSES_XML = get_sample( + "setropts_remove_generic_command_processing_classes.xml" +) +TEST_SETROPTS_ADD_GENERIC_PROFILE_CHECKING_CLASSES_XML = get_sample( + "setropts_add_generic_profile_checking_classes.xml" +) +TEST_SETROPTS_REMOVE_GENERIC_PROFILE_CHECKING_CLASSES_XML = get_sample( + "setropts_remove_generic_profile_checking_classes.xml" +) +TEST_SETROPTS_ADD_GENERIC_PROFILE_SHARING_CLASSES_XML = get_sample( + "setropts_add_generic_profile_sharing_classes.xml" +) +TEST_SETROPTS_REMOVE_GENERIC_PROFILE_SHARING_CLASSES_XML = get_sample( + "setropts_remove_generic_profile_sharing_classes.xml" +) +TEST_SETROPTS_ADD_GLOBAL_ACCESS_CLASSES_XML = get_sample( + "setropts_add_global_access_classes.xml" +) +TEST_SETROPTS_REMOVE_GLOBAL_ACCESS_CLASSES_XML = get_sample( + "setropts_remove_global_access_classes.xml" +) +TEST_SETROPTS_ADD_RACLIST_CLASSES_XML = get_sample("setropts_add_raclist_classes.xml") +TEST_SETROPTS_REMOVE_RACLIST_CLASSES_XML = get_sample( + "setropts_remove_raclist_classes.xml" +) +TEST_SETROPTS_REFRESH_RACLIST_MULTIPLE_XML = get_sample( + "setropts_refresh_raclist_multiple.xml" +) # ============================================================================ # Setropts Administration Getters Comparison Data diff --git a/tests/setropts/test_setropts_setters.py b/tests/setropts/test_setropts_setters.py index 14e7d7b6..4c7c44e3 100644 --- a/tests/setropts/test_setropts_setters.py +++ b/tests/setropts/test_setropts_setters.py @@ -72,6 +72,132 @@ def test_setropts_admin_build_add_raclist_class_request(self): result, TestSetroptsConstants.TEST_SETROPTS_ADD_RACLIST_CLASS_XML ) + def test_setropts_admin_build_add_audit_classes_request_string(self): + result = self.setropts_admin.add_audit_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_AUDIT_CLASSES_XML + ) + + def test_setropts_admin_build_add_active_classes_request_string(self): + result = self.setropts_admin.add_active_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_ACTIVE_CLASSES_XML + ) + + def test_setropts_admin_build_add_statistics_classes_request_string(self): + result = self.setropts_admin.add_statistics_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_STATISTICS_CLASSES_XML + ) + + def test_setropts_admin_build_add_generic_command_processing_classes_request_string( + self, + ): + result = self.setropts_admin.add_generic_command_processing_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_COMMAND_PROCESSING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_generic_profile_checking_classes_request_string( + self, + ): + result = self.setropts_admin.add_generic_profile_checking_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_CHECKING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_generic_profile_sharing_classes_request_string( + self, + ): + result = self.setropts_admin.add_generic_profile_sharing_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_SHARING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_global_access_classes_request_string(self): + result = self.setropts_admin.add_global_access_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_GLOBAL_ACCESS_CLASSES_XML + ) + + def test_setropts_admin_build_add_raclist_classes_request_string(self): + result = self.setropts_admin.add_raclist_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_RACLIST_CLASSES_XML + ) + + def test_setropts_admin_build_add_audit_classes_request_list(self): + result = self.setropts_admin.add_audit_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_AUDIT_CLASSES_XML + ) + + def test_setropts_admin_build_add_active_classes_request_list(self): + result = self.setropts_admin.add_active_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_ACTIVE_CLASSES_XML + ) + + def test_setropts_admin_build_add_statistics_classes_request_list(self): + result = self.setropts_admin.add_statistics_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_STATISTICS_CLASSES_XML + ) + + def test_setropts_admin_build_add_generic_command_processing_classes_request_list( + self, + ): + result = self.setropts_admin.add_generic_command_processing_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_COMMAND_PROCESSING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_generic_profile_checking_classes_request_list( + self, + ): + result = self.setropts_admin.add_generic_profile_checking_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_CHECKING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_generic_profile_sharing_classes_request_list( + self, + ): + result = self.setropts_admin.add_generic_profile_sharing_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_ADD_GENERIC_PROFILE_SHARING_CLASSES_XML, + ) + + def test_setropts_admin_build_add_global_access_classes_request_list(self): + result = self.setropts_admin.add_global_access_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_GLOBAL_ACCESS_CLASSES_XML + ) + + def test_setropts_admin_build_add_raclist_classes_request_list(self): + result = self.setropts_admin.add_raclist_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_ADD_RACLIST_CLASSES_XML + ) + # ============================================================================ # Class removers # ============================================================================ @@ -128,6 +254,134 @@ def test_setropts_admin_build_remove_raclist_class_request(self): result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_RACLIST_CLASS_XML ) + def test_setropts_admin_build_remove_audit_classes_request_string(self): + result = self.setropts_admin.remove_audit_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_AUDIT_CLASSES_XML + ) + + def test_setropts_admin_build_remove_active_classes_request_string(self): + result = self.setropts_admin.remove_active_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_ACTIVE_CLASSES_XML + ) + + def test_setropts_admin_build_remove_statistics_classes_request_string(self): + result = self.setropts_admin.remove_statistics_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_STATISTICS_CLASSES_XML + ) + + def test_setropts_admin_build_remove_generic_command_processing_classes_request_string( + self, + ): + result = self.setropts_admin.remove_generic_command_processing_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_COMMAND_PROCESSING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_generic_profile_checking_classes_request_string( + self, + ): + result = self.setropts_admin.remove_generic_profile_checking_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_CHECKING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_generic_profile_sharing_classes_request_string( + self, + ): + result = self.setropts_admin.remove_generic_profile_sharing_classes( + "elijtest xfacilit" + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_SHARING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_global_access_classes_request_string(self): + result = self.setropts_admin.remove_global_access_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GLOBAL_ACCESS_CLASSES_XML + ) + + def test_setropts_admin_build_remove_raclist_classes_request_string(self): + result = self.setropts_admin.remove_raclist_classes("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_RACLIST_CLASSES_XML + ) + + def test_setropts_admin_build_remove_audit_classes_request_list(self): + result = self.setropts_admin.remove_audit_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_AUDIT_CLASSES_XML + ) + + def test_setropts_admin_build_remove_active_classes_request_list(self): + result = self.setropts_admin.remove_active_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_ACTIVE_CLASSES_XML + ) + + def test_setropts_admin_build_remove_statistics_classes_request_list(self): + result = self.setropts_admin.remove_statistics_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_STATISTICS_CLASSES_XML + ) + + def test_setropts_admin_build_remove_generic_command_processing_classes_request_list( + self, + ): + result = self.setropts_admin.remove_generic_command_processing_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_COMMAND_PROCESSING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_generic_profile_checking_classes_request_list( + self, + ): + result = self.setropts_admin.remove_generic_profile_checking_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_CHECKING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_generic_profile_sharing_classes_request_list( + self, + ): + result = self.setropts_admin.remove_generic_profile_sharing_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, + TestSetroptsConstants.TEST_SETROPTS_REMOVE_GENERIC_PROFILE_SHARING_CLASSES_XML, + ) + + def test_setropts_admin_build_remove_global_access_classes_request_list(self): + result = self.setropts_admin.remove_global_access_classes( + ["elijtest", "xfacilit"] + ) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_GLOBAL_ACCESS_CLASSES_XML + ) + + def test_setropts_admin_build_remove_raclist_classes_request_list(self): + result = self.setropts_admin.remove_raclist_classes(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REMOVE_RACLIST_CLASSES_XML + ) + # ============================================================================ # Raclist refresh # ============================================================================ @@ -136,3 +390,15 @@ def test_setropts_admin_build_refresh_raclist_request(self): self.assertEqual( result, TestSetroptsConstants.TEST_SETROPTS_REFRESH_RACLIST_XML ) + + def test_setropts_admin_build_refresh_raclist_multiple_request_list(self): + result = self.setropts_admin.refresh_raclist(["elijtest", "xfacilit"]) + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REFRESH_RACLIST_MULTIPLE_XML + ) + + def test_setropts_admin_build_refresh_raclist_multiple_request_string(self): + result = self.setropts_admin.refresh_raclist("elijtest xfacilit") + self.assertEqual( + result, TestSetroptsConstants.TEST_SETROPTS_REFRESH_RACLIST_MULTIPLE_XML + ) From 1b1a1bdf4d1b78c15fbc9af5978af345500c9579 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 26 Oct 2023 15:18:13 -0400 Subject: [PATCH 43/72] Move Testing of Debug Logging to Alter Move Testing of debug logging to Alter in Group, DataSet and Resource Admins Signed-off-by: Elijah Swift --- pyracf/data_set/data_set_admin.py | 22 +- pyracf/group/group_admin.py | 24 +- pyracf/resource/resource_admin.py | 24 +- pyracf/user/user_admin.py | 2 +- .../add_data_set_error.log | 101 ------- .../add_data_set_success.log | 93 ------ .../alter_data_set_error.log | 265 ++++++++++++++++++ .../alter_data_set_success.log | 249 ++++++++++++++++ ...g => extract_data_set_base_only_error.log} | 0 ...=> extract_data_set_base_only_success.log} | 0 .../add_data_set_result_error.json | 17 +- .../add_data_set_result_error.xml | 15 +- ...ract_data_set_result_base_only_error.json} | 0 ...tract_data_set_result_base_only_error.xml} | 0 ...ct_data_set_result_base_only_success.json} | 0 ...act_data_set_result_base_only_success.xml} | 0 ...set_result_generic_base_only_success.json} | 0 ..._set_result_generic_base_only_success.xml} | 0 ...ta_set_result_invalid_attribute_error.json | 25 ++ ...ata_set_result_invalid_attribute_error.xml | 16 ++ tests/data_set/test_data_set_constants.py | 42 +-- tests/data_set/test_data_set_debug_logging.py | 43 +-- tests/data_set/test_data_set_getters.py | 12 +- tests/data_set/test_data_set_result_parser.py | 73 +++-- .../group_log_samples/add_group_error.log | 91 ------ .../group_log_samples/add_group_success.log | 87 ------ .../group_log_samples/alter_group_error.log | 243 ++++++++++++++++ .../group_log_samples/alter_group_success.log | 235 ++++++++++++++++ .../add_group_result_error.json | 31 +- .../add_group_result_error.xml | 27 +- .../extract_group_result_base_only_error.json | 22 ++ .../extract_group_result_base_only_error.xml | 14 + ..._group_result_invalid_attribute_error.json | 19 ++ ...t_group_result_invalid_attribute_error.xml | 15 + tests/group/test_group_constants.py | 16 +- tests/group/test_group_debug_logging.py | 31 +- tests/group/test_group_result_parser.py | 46 ++- .../add_resource_error.log | 107 ------- .../add_resource_success.log | 101 ------- .../alter_resource_error.log | 253 +++++++++++++++++ .../alter_resource_success.log | 249 ++++++++++++++++ ...t_resource_result_invalid_class_error.json | 25 ++ ...ct_resource_result_invalid_class_error.xml | 16 ++ tests/resource/test_resource_constants.py | 10 +- tests/resource/test_resource_debug_logging.py | 34 +-- tests/resource/test_resource_result_parser.py | 46 ++- tests/user/test_user_result_parser.py | 28 +- 47 files changed, 1996 insertions(+), 773 deletions(-) delete mode 100644 tests/data_set/data_set_log_samples/add_data_set_error.log delete mode 100644 tests/data_set/data_set_log_samples/add_data_set_success.log create mode 100644 tests/data_set/data_set_log_samples/alter_data_set_error.log create mode 100644 tests/data_set/data_set_log_samples/alter_data_set_success.log rename tests/data_set/data_set_log_samples/{extract_data_set_base_error.log => extract_data_set_base_only_error.log} (100%) rename tests/data_set/data_set_log_samples/{extract_data_set_base_success.log => extract_data_set_base_only_success.log} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_base_error.json => extract_data_set_result_base_only_error.json} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_base_error.xml => extract_data_set_result_base_only_error.xml} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_base_success.json => extract_data_set_result_base_only_success.json} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_base_success.xml => extract_data_set_result_base_only_success.xml} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_generic_base_success.json => extract_data_set_result_generic_base_only_success.json} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_generic_base_success.xml => extract_data_set_result_generic_base_only_success.xml} (100%) create mode 100644 tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json create mode 100644 tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml delete mode 100644 tests/group/group_log_samples/add_group_error.log delete mode 100644 tests/group/group_log_samples/add_group_success.log create mode 100644 tests/group/group_log_samples/alter_group_error.log create mode 100644 tests/group/group_log_samples/alter_group_success.log create mode 100644 tests/group/group_result_samples/extract_group_result_base_only_error.json create mode 100644 tests/group/group_result_samples/extract_group_result_base_only_error.xml create mode 100644 tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json create mode 100644 tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml delete mode 100644 tests/resource/resource_log_samples/add_resource_error.log delete mode 100644 tests/resource/resource_log_samples/add_resource_success.log create mode 100644 tests/resource/resource_log_samples/alter_resource_error.log create mode 100644 tests/resource/resource_log_samples/alter_resource_success.log create mode 100644 tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json create mode 100644 tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 359d3167..1610617e 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -2,6 +2,7 @@ from typing import List, Union +from pyracf.common.add_operation_error import AddOperationError from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin from pyracf.common.security_request_error import SecurityRequestError @@ -99,15 +100,26 @@ def get_my_access(self, data_set: str) -> Union[str, bytes, None]: def add( self, data_set: str, - traits: dict, + traits: dict = {}, volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: """Create a new data set profile.""" - self._build_segment_dictionaries(traits) - data_set_request = DataSetRequest(data_set, "set", volume, generic) - self._build_xml_segments(data_set_request) - return self._make_request(data_set_request) + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + data_set_request = DataSetRequest(data_set, "set", volume, generic) + self._build_xml_segments(data_set_request) + return self._make_request(data_set_request) + try: + self.extract(data_set, volume=volume, generic=generic) + except SecurityRequestError as exception: + if not exception.scan_for_error("dataSet", "ICH35003I"): + raise exception + self._build_segment_dictionaries(traits) + data_set_request = DataSetRequest(data_set, "set", volume, generic) + self._build_xml_segments(data_set_request) + return self._make_request(data_set_request) + raise AddOperationError(data_set, "DATASET") def alter( self, diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index 58a5f597..fde464f3 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -2,6 +2,7 @@ from typing import List, Union +from pyracf.common.add_operation_error import AddOperationError from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin from pyracf.common.security_request_error import SecurityRequestError @@ -121,12 +122,23 @@ def set_ovm_gid(self, group: str, gid: int) -> Union[dict, bytes]: # ============================================================================ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new group.""" - self._build_segment_dictionaries(traits) - group_request = GroupRequest(group, "set") - self._build_xml_segments(group_request) - return self._make_request(group_request) - - def alter(self, group: str, traits: dict = {}) -> Union[dict, bytes]: + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + group_request = GroupRequest(group, "set") + self._build_xml_segments(group_request) + return self._make_request(group_request) + try: + self.extract(group) + except SecurityRequestError as exception: + if not exception.scan_for_error("group", "ICH51003I"): + raise exception + self._build_segment_dictionaries(traits) + group_request = GroupRequest(group, "set") + self._build_xml_segments(group_request) + return self._make_request(group_request) + raise AddOperationError(group, "GROUP") + + def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" try: self.extract(group) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 0d9eb7a5..59c388da 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -2,6 +2,7 @@ from typing import List, Union +from pyracf.common.add_operation_error import AddOperationError from pyracf.common.alter_operation_error import AlterOperationError from pyracf.common.security_admin import SecurityAdmin from pyracf.common.security_request_error import SecurityRequestError @@ -222,14 +223,23 @@ def add( self, resource: str, class_name: str, traits: dict = {} ) -> Union[dict, bytes]: """Create a new general resource profile.""" - self._build_segment_dictionaries(traits) - profile_request = ResourceRequest(resource, class_name, "set") - self._build_xml_segments(profile_request) - return self._make_request(profile_request) + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + profile_request = ResourceRequest(resource, class_name, "set") + self._build_xml_segments(profile_request) + return self._make_request(profile_request) + try: + self.extract(resource, class_name) + except SecurityRequestError as exception: + if not exception.scan_for_error("resource", "ICH13003I"): + raise exception + self._build_segment_dictionaries(traits) + profile_request = ResourceRequest(resource, class_name, "set") + self._build_xml_segments(profile_request) + return self._make_request(profile_request) + raise AddOperationError(resource, class_name) - def alter( - self, resource: str, class_name: str, traits: dict = {} - ) -> Union[dict, bytes]: + def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, bytes]: """Alter an existing general resource profile.""" try: self.extract(resource, class_name) diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index ff806e17..8db20d69 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -784,7 +784,7 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: return self._make_request(user_request) raise AddOperationError(userid, "USER") - def alter(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: + def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: """Alter an existing user.""" if self._generate_requests_only: self._build_segment_dictionaries(traits) diff --git a/tests/data_set/data_set_log_samples/add_data_set_error.log b/tests/data_set/data_set_log_samples/add_data_set_error.log deleted file mode 100644 index 24b52aed..00000000 --- a/tests/data_set/data_set_log_samples/add_data_set_error.log +++ /dev/null @@ -1,101 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - DataSetAdmin.add() - - -{ - "base": { - "base:universal_access": { - "value": "None", - "operation": null - }, - "base:owner": { - "value": "eswift", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - DataSetAdmin.add() - - - - - - None - eswift - - - - - - [pyRACF:Debug] - Result XML - DataSetAdmin.add() - - - - - - - 8 - 16 - 4 - ADDSD ('ESWIFF.TEST.T1136242.P3020470') - ICH09006I USER OR GROUP ESWIFF NOT DEFINED TO RACF - - - 8 - 16 - 4 - ALTDSD ('ESWIFF.TEST.T1136242.P3020470') UACC (None) OWNER (eswift) - ICH22001I ESWIFF.TEST.T1136242.P3020470 NOT DEFINED TO RACF - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - DataSetAdmin.add() - - -{ - "securityResult": { - "dataSet": { - "name": "ESWIFF.TEST.T1136242.P3020470", - "operation": "set", - "generic": "no", - "requestId": "DatasetRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 4, - "image": "ADDSD ('ESWIFF.TEST.T1136242.P3020470')", - "messages": [ - "ICH09006I USER OR GROUP ESWIFF NOT DEFINED TO RACF" - ] - }, - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 4, - "image": "ALTDSD ('ESWIFF.TEST.T1136242.P3020470') UACC (None) OWNER (eswift)", - "messages": [ - "ICH22001I ESWIFF.TEST.T1136242.P3020470 NOT DEFINED TO RACF" - ] - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/data_set/data_set_log_samples/add_data_set_success.log b/tests/data_set/data_set_log_samples/add_data_set_success.log deleted file mode 100644 index 47501b50..00000000 --- a/tests/data_set/data_set_log_samples/add_data_set_success.log +++ /dev/null @@ -1,93 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - DataSetAdmin.add() - - -{ - "base": { - "base:universal_access": { - "value": "None", - "operation": null - }, - "base:owner": { - "value": "eswift", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - DataSetAdmin.add() - - - - - - None - eswift - - - - - - [pyRACF:Debug] - Result XML - DataSetAdmin.add() - - - - - - - 0 - 0 - 0 - ADDSD ('ESWIFT.TEST.T1136242.P3020470') - - - 0 - 0 - 0 - ALTDSD ('ESWIFT.TEST.T1136242.P3020470') UACC (None) OWNER (eswift) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - DataSetAdmin.add() - - -{ - "securityResult": { - "dataSet": { - "name": "ESWIFT.TEST.T1136242.P3020470", - "operation": "set", - "generic": "no", - "requestId": "DatasetRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDSD ('ESWIFT.TEST.T1136242.P3020470')" - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTDSD ('ESWIFT.TEST.T1136242.P3020470') UACC (None) OWNER (eswift)" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/data_set/data_set_log_samples/alter_data_set_error.log b/tests/data_set/data_set_log_samples/alter_data_set_error.log new file mode 100644 index 00000000..e637e65f --- /dev/null +++ b/tests/data_set/data_set_log_samples/alter_data_set_error.log @@ -0,0 +1,265 @@ + + [pyRACF:Debug] + Request Dictionary + DataSetAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + DataSetAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + DataSetAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470') + INFORMATION FOR DATASET ESWIFT.TEST.T1136242.P3020470 + + LEVEL OWNER UNIVERSAL ACCESS WARNING ERASE + ----- -------- ---------------- ------- ----- + 00 ESWIFT READ NO NO + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + -------- + NO USER TO BE NOTIFIED + + YOUR ACCESS CREATION GROUP DATASET TYPE + ----------- -------------- ------------ + ALTER SYS1 NON-VSAM + + VOLUMES ON WHICH DATASET RESIDES + -------------------------------- + USRAT2 + + NO INSTALLATION DATA + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T1136242.P3020470", + "operation": "listdata", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470')", + "messages": [ + "INFORMATION FOR DATASET ESWIFT.TEST.T1136242.P3020470", + null, + "LEVEL OWNER UNIVERSAL ACCESS WARNING ERASE", + "----- -------- ---------------- ------- -----", + " 00 ESWIFT READ NO NO", + null, + "AUDITING", + "--------", + "FAILURES(READ)", + null, + "NOTIFY", + "--------", + "NO USER TO BE NOTIFIED", + null, + "YOUR ACCESS CREATION GROUP DATASET TYPE", + "----------- -------------- ------------", + " ALTER SYS1 NON-VSAM", + null, + "VOLUMES ON WHICH DATASET RESIDES", + "--------------------------------", + "USRAT2", + null, + "NO INSTALLATION DATA" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T1136242.P3020470", + "operation": "listdata", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470')", + "profiles": [ + { + "base": { + "name": "eswift.test.t1136242.p3020470", + "level": 0, + "owner": "eswift", + "universalAccess": "read", + "warning": null, + "erase": null, + "auditing": { + "failures": "read" + }, + "notify": null, + "yourAccess": "alter", + "creationGroup": "sys1", + "dataSetType": "non-vsam", + "volumes": [ + "usrat2" + ], + "installationData": null, + "generic": false + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + DataSetAdmin.alter() + + +{ + "base": { + "base:universal_access": { + "value": "Read", + "operation": null + }, + "base:owner": { + "value": "eswift", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + DataSetAdmin.alter() + + + + + + Read + eswift + + + + + + [pyRACF:Debug] + Result XML + DataSetAdmin.alter() + + + + + + + 8 + 16 + 4 + ADDSD ('ESWIFT.TEST.T113622.P3020470') + ICH09005I ESWIFT.TEST.T113622.P3020470 NOT FOUND IN CATALOG + + + 8 + 16 + 4 + ALTDSD ('ESWIFT.TEST.T113622.P3020470') UACC (ALTER) + ICH22001I ESWIFT.TEST.T113622.P3020470 NOT DEFINED TO RACF + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T113622.P3020470", + "operation": "set", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 4, + "image": "ADDSD ('ESWIFT.TEST.T113622.P3020470')", + "messages": [ + "ICH09005I ESWIFT.TEST.T113622.P3020470 NOT FOUND IN CATALOG" + ] + }, + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 4, + "image": "ALTDSD ('ESWIFT.TEST.T113622.P3020470') UACC (ALTER)", + "messages": [ + "ICH22001I ESWIFT.TEST.T113622.P3020470 NOT DEFINED TO RACF" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/data_set/data_set_log_samples/alter_data_set_success.log b/tests/data_set/data_set_log_samples/alter_data_set_success.log new file mode 100644 index 00000000..131978a6 --- /dev/null +++ b/tests/data_set/data_set_log_samples/alter_data_set_success.log @@ -0,0 +1,249 @@ + + [pyRACF:Debug] + Request Dictionary + DataSetAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + DataSetAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + DataSetAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470') + INFORMATION FOR DATASET ESWIFT.TEST.T1136242.P3020470 + + LEVEL OWNER UNIVERSAL ACCESS WARNING ERASE + ----- -------- ---------------- ------- ----- + 00 ESWIFT READ NO NO + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + -------- + NO USER TO BE NOTIFIED + + YOUR ACCESS CREATION GROUP DATASET TYPE + ----------- -------------- ------------ + ALTER SYS1 NON-VSAM + + VOLUMES ON WHICH DATASET RESIDES + -------------------------------- + USRAT2 + + NO INSTALLATION DATA + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T1136242.P3020470", + "operation": "listdata", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470')", + "messages": [ + "INFORMATION FOR DATASET ESWIFT.TEST.T1136242.P3020470", + null, + "LEVEL OWNER UNIVERSAL ACCESS WARNING ERASE", + "----- -------- ---------------- ------- -----", + " 00 ESWIFT READ NO NO", + null, + "AUDITING", + "--------", + "FAILURES(READ)", + null, + "NOTIFY", + "--------", + "NO USER TO BE NOTIFIED", + null, + "YOUR ACCESS CREATION GROUP DATASET TYPE", + "----------- -------------- ------------", + " ALTER SYS1 NON-VSAM", + null, + "VOLUMES ON WHICH DATASET RESIDES", + "--------------------------------", + "USRAT2", + null, + "NO INSTALLATION DATA" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T1136242.P3020470", + "operation": "listdata", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTDSD DATASET ('ESWIFT.TEST.T1136242.P3020470')", + "profiles": [ + { + "base": { + "name": "eswift.test.t1136242.p3020470", + "level": 0, + "owner": "eswift", + "universalAccess": "read", + "warning": null, + "erase": null, + "auditing": { + "failures": "read" + }, + "notify": null, + "yourAccess": "alter", + "creationGroup": "sys1", + "dataSetType": "non-vsam", + "volumes": [ + "usrat2" + ], + "installationData": null, + "generic": false + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + DataSetAdmin.alter() + + +{ + "base": { + "base:universal_access": { + "value": "Read", + "operation": null + }, + "base:owner": { + "value": "eswift", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + DataSetAdmin.alter() + + + + + + Read + eswift + + + + + + [pyRACF:Debug] + Result XML + DataSetAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTDSD ('ESWIFT.TEST.T1136242.P3020470') UACC (Read) OWNER (eswift) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + DataSetAdmin.alter() + + +{ + "securityResult": { + "dataSet": { + "name": "ESWIFT.TEST.T1136242.P3020470", + "operation": "set", + "generic": "no", + "requestId": "DatasetRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTDSD ('ESWIFT.TEST.T1136242.P3020470') UACC (Read) OWNER (eswift)" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/data_set/data_set_log_samples/extract_data_set_base_error.log b/tests/data_set/data_set_log_samples/extract_data_set_base_only_error.log similarity index 100% rename from tests/data_set/data_set_log_samples/extract_data_set_base_error.log rename to tests/data_set/data_set_log_samples/extract_data_set_base_only_error.log diff --git a/tests/data_set/data_set_log_samples/extract_data_set_base_success.log b/tests/data_set/data_set_log_samples/extract_data_set_base_only_success.log similarity index 100% rename from tests/data_set/data_set_log_samples/extract_data_set_base_success.log rename to tests/data_set/data_set_log_samples/extract_data_set_base_only_success.log diff --git a/tests/data_set/data_set_result_samples/add_data_set_result_error.json b/tests/data_set/data_set_result_samples/add_data_set_result_error.json index 263aefe9..ed2fc26a 100644 --- a/tests/data_set/data_set_result_samples/add_data_set_result_error.json +++ b/tests/data_set/data_set_result_samples/add_data_set_result_error.json @@ -1,7 +1,7 @@ { "securityResult": { "dataSet": { - "name": "ESWIFF.TEST.T1136242.P3020470", + "name": "ESWIFTTESTT1136242P3020470", "operation": "set", "generic": "no", "requestId": "DatasetRequest", @@ -9,19 +9,10 @@ { "safReturnCode": 8, "returnCode": 16, - "reasonCode": 4, - "image": "ADDSD ('ESWIFF.TEST.T1136242.P3020470')", + "reasonCode": 8, + "image": "ADDSD ('ESWIFTTESTT1136242P3020470') ", "messages": [ - "ICH09006I USER OR GROUP ESWIFF NOT DEFINED TO RACF" - ] - }, - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 4, - "image": "ALTDSD ('ESWIFF.TEST.T1136242.P3020470') UACC (None) OWNER (eswift)", - "messages": [ - "ICH22001I ESWIFF.TEST.T1136242.P3020470 NOT DEFINED TO RACF" + "IKJ56702I INVALID DATASET NAME, 'ESWIFTTESTT1136242P3020470'" ] } ] diff --git a/tests/data_set/data_set_result_samples/add_data_set_result_error.xml b/tests/data_set/data_set_result_samples/add_data_set_result_error.xml index dd9ba686..2b86b12a 100644 --- a/tests/data_set/data_set_result_samples/add_data_set_result_error.xml +++ b/tests/data_set/data_set_result_samples/add_data_set_result_error.xml @@ -1,19 +1,12 @@ - + 8 16 - 4 - ADDSD ('ESWIFF.TEST.T1136242.P3020470') - ICH09006I USER OR GROUP ESWIFF NOT DEFINED TO RACF - - - 8 - 16 - 4 - ALTDSD ('ESWIFF.TEST.T1136242.P3020470') UACC (None) OWNER (eswift) - ICH22001I ESWIFF.TEST.T1136242.P3020470 NOT DEFINED TO RACF + 8 + ADDSD ('ESWIFFTESTT1136242P3020470') + IKJ56702I INVALID DATASET NAME, 'ESWIFFTESTT1136242P3020470' 4 diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_base_error.json b/tests/data_set/data_set_result_samples/extract_data_set_result_base_only_error.json similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_base_error.json rename to tests/data_set/data_set_result_samples/extract_data_set_result_base_only_error.json diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_base_error.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_base_only_error.xml similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_base_error.xml rename to tests/data_set/data_set_result_samples/extract_data_set_result_base_only_error.xml diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_base_success.json b/tests/data_set/data_set_result_samples/extract_data_set_result_base_only_success.json similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_base_success.json rename to tests/data_set/data_set_result_samples/extract_data_set_result_base_only_success.json diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_base_success.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_base_only_success.xml similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_base_success.xml rename to tests/data_set/data_set_result_samples/extract_data_set_result_base_only_success.xml diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_success.json b/tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_only_success.json similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_success.json rename to tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_only_success.json diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_success.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_only_success.xml similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_success.xml rename to tests/data_set/data_set_result_samples/extract_data_set_result_generic_base_only_success.xml diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json b/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json new file mode 100644 index 00000000..b5d84c93 --- /dev/null +++ b/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json @@ -0,0 +1,25 @@ +{ + "securityResult": { + "dataSet": { + "name": "ESWIFTTESTT1136242P3020470", + "operation": "listdata", + "generic": "no", + "requestId": "DatasetRequest", + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "LISTDSD DATASET ('ESWIFTTESTT1136242P3020470') ", + "messages": [ + "IKJ56702I INVALID DATASET NAME, 'ESWIFTTESTT1136242P3020470'", + "IKJ56701I MISSING DATASET NAME+", + "IKJ56701I MISSING DATASET NAMES FOR WHICH YOU WANT RACF INFORMATION LISTED" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml new file mode 100644 index 00000000..3a0a02de --- /dev/null +++ b/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml @@ -0,0 +1,16 @@ + + + + + 8 + 16 + 8 + LISTDSD DATASET ('ESWIFTTESTT1136242P3020470') + IKJ56702I INVALID DATASET NAME, 'ESWIFTTESTT1136242P3020470' + IKJ56701I MISSING DATASET NAME+ + IKJ56701I MISSING DATASET NAMES FOR WHICH YOU WANT RACF INFORMATION LISTED + + + 4 + 0 + \ No newline at end of file diff --git a/tests/data_set/test_data_set_constants.py b/tests/data_set/test_data_set_constants.py index b4801ded..d68a090a 100644 --- a/tests/data_set/test_data_set_constants.py +++ b/tests/data_set/test_data_set_constants.py @@ -40,23 +40,29 @@ def get_sample(sample_file: str) -> Union[str, bytes]: ) # Extract Data Set -TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML = get_sample( - "extract_data_set_result_base_success.xml" +TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_data_set_result_base_only_success.xml" ) -TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_DICTIONARY = get_sample( - "extract_data_set_result_base_success.json" +TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_DICTIONARY = get_sample( + "extract_data_set_result_base_only_success.json" ) -TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_SUCCESS_XML = get_sample( - "extract_data_set_result_generic_base_success.xml" +TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_XML = get_sample( + "extract_data_set_result_generic_base_only_success.xml" ) -TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_SUCCESS_DICTIONARY = get_sample( - "extract_data_set_result_generic_base_success.json" +TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_DICTIONARY = get_sample( + "extract_data_set_result_generic_base_only_success.json" ) -TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML = get_sample( - "extract_data_set_result_base_error.xml" +TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML = get_sample( + "extract_data_set_result_base_only_error.xml" ) -TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_DICTIONARY = get_sample( - "extract_data_set_result_base_error.json" +TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_DICTIONARY = get_sample( + "extract_data_set_result_base_only_error.json" +) +TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_XML = get_sample( + "extract_data_set_result_invalid_attribute_error.xml" +) +TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY = get_sample( + "extract_data_set_result_invalid_attribute_error.json" ) # Delete Data Set @@ -118,8 +124,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_DATA_SET_SUCCESS_LOG = get_sample("add_data_set_success.log") -TEST_ADD_DATA_SET_ERROR_LOG = get_sample("add_data_set_error.log") +TEST_ALTER_DATA_SET_SUCCESS_LOG = get_sample("alter_data_set_success.log") +TEST_ALTER_DATA_SET_ERROR_LOG = get_sample("alter_data_set_error.log") -TEST_EXTRACT_DATA_SET_BASE_SUCCESS_LOG = get_sample("extract_data_set_base_success.log") -TEST_EXTRACT_DATA_SET_BASE_ERROR_LOG = get_sample("extract_data_set_base_error.log") +TEST_EXTRACT_DATA_SET_BASE_ONLY_SUCCESS_LOG = get_sample( + "extract_data_set_base_only_success.log" +) +TEST_EXTRACT_DATA_SET_BASE_ONLY_ERROR_LOG = get_sample( + "extract_data_set_base_only_error.log" +) diff --git a/tests/data_set/test_data_set_debug_logging.py b/tests/data_set/test_data_set_debug_logging.py index e5fa2a9d..01a13452 100644 --- a/tests/data_set/test_data_set_debug_logging.py +++ b/tests/data_set/test_data_set_debug_logging.py @@ -24,44 +24,46 @@ class TestDataSetDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Data Set + # Alter Data Set # ============================================================================ - def test_add_data_set_request_debug_log_works_on_success( + def test_alter_data_set_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.data_set_admin.add( + self.data_set_admin.alter( "ESWIFT.TEST.T1136242.P3020470", - traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, + traits=TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestDataSetConstants.TEST_ADD_DATA_SET_SUCCESS_LOG + success_log, TestDataSetConstants.TEST_ALTER_DATA_SET_SUCCESS_LOG ) - def test_add_data_set_request_debug_log_works_on_error( + def test_alter_data_set_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.data_set_admin.add( - "ESWIFF.TEST.T1136242.P3020470", - traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, + self.data_set_admin.alter( + "ESWIFT.TEST.T1136242.P3020470", + traits=TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestDataSetConstants.TEST_ADD_DATA_SET_ERROR_LOG) + self.assertEqual(error_log, TestDataSetConstants.TEST_ALTER_DATA_SET_ERROR_LOG) # ============================================================================ # Extract Data Set @@ -71,14 +73,15 @@ def test_extract_data_set_base_request_debug_log_works_on_success( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): self.data_set_admin.extract("ESWIFT.TEST.T1136242.P3020470") success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestDataSetConstants.TEST_EXTRACT_DATA_SET_BASE_SUCCESS_LOG + success_log, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_BASE_ONLY_SUCCESS_LOG, ) def test_extract_data_set_base_request_debug_log_works_on_error( @@ -86,7 +89,7 @@ def test_extract_data_set_base_request_debug_log_works_on_error( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): @@ -96,5 +99,5 @@ def test_extract_data_set_base_request_debug_log_works_on_error( pass error_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - error_log, TestDataSetConstants.TEST_EXTRACT_DATA_SET_BASE_ERROR_LOG + error_log, TestDataSetConstants.TEST_EXTRACT_DATA_SET_BASE_ONLY_ERROR_LOG ) diff --git a/tests/data_set/test_data_set_getters.py b/tests/data_set/test_data_set_getters.py index 8e630eb5..0437b283 100644 --- a/tests/data_set/test_data_set_getters.py +++ b/tests/data_set/test_data_set_getters.py @@ -27,7 +27,7 @@ def test_data_set_admin_get_universal_access_returns_valid_when_read( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.data_set_admin.get_universal_access("ESWIFT.TEST.T1136242.P3020470"), @@ -39,7 +39,7 @@ def test_data_set_admin_get_universal_access_returns_valid_when_none( call_racf_mock: Mock, ): data_set_extract_no_universal_access = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) data_set_extract_no_universal_access = ( data_set_extract_no_universal_access.replace( @@ -58,7 +58,7 @@ def test_data_set_admin_get_universal_access_raises_an_exception_when_extract_fa call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML ) with self.assertRaises(SecurityRequestError): self.data_set_admin.get_universal_access("ESWIFT.TEST.T1136242.P3020470") @@ -68,7 +68,7 @@ def test_data_set_admin_get_my_access_returns_valid_when_alter( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.data_set_admin.get_my_access("ESWIFT.TEST.T1136242.P3020470"), "alter" @@ -79,7 +79,7 @@ def test_data_set_admin_get_my_access_returns_valid_when_none( call_racf_mock: Mock, ): data_set_extract_no_my_access = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) data_set_extract_no_my_access = data_set_extract_no_my_access.replace( " ALTER SYS1 NON-VSAM", @@ -96,7 +96,7 @@ def test_data_set_admin_get_my_access_raises_an_exception_when_extract_fails( call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML ) with self.assertRaises(SecurityRequestError): self.data_set_admin.get_my_access("ESWIFT.TEST.T1136242.P3020470") diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 1dae2aa3..48aaca27 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -6,7 +6,12 @@ import __init__ import tests.data_set.test_data_set_constants as TestDataSetConstants -from pyracf import AlterOperationError, DataSetAdmin, SecurityRequestError +from pyracf import ( + AddOperationError, + AlterOperationError, + DataSetAdmin, + SecurityRequestError, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -26,9 +31,10 @@ def test_data_set_admin_can_parse_add_data_set_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML, + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML, + ] self.assertEqual( self.data_set_admin.add( "ESWIFT.TEST.T1136242.P3020470", @@ -37,22 +43,45 @@ def test_data_set_admin_can_parse_add_data_set_success_xml( TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_DICTIONARY, ) - # Error User or Group ESWIFF not defined to RACF - def test_data_set_admin_can_parse_add_data_set_error_xml( + def test_data_set_admin_thows_error_on_add_existing_data_set_profile( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML + profile_name = "ESWIFT.TEST.T1136242.P3020470" + class_name = "DATASET" + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AddOperationError) as exception: + self.data_set_admin.add( + profile_name, + traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' already exists as a {class_name} profile.", ) + + # Error in command, ESWIFTTESTT1136242P3020470 is not a valid DATASET + def test_data_set_admin_can_parse_add_data_set_error_xml( + self, + call_racf_mock: Mock, + ): + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_XML, + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.data_set_admin.add( - "ESWIFF.TEST.T1136242.P3020470", + "ESWIFTTESTT1136242P3020470", traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, ) self.assertEqual( exception.exception.result, - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ @@ -63,7 +92,7 @@ def test_data_set_admin_can_parse_alter_data_set_success_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, ] self.assertEqual( @@ -81,7 +110,7 @@ def test_data_set_admin_thows_error_on_alter_new_data_set_profile( profile_name = "ESWIFT.TEST.T1136242.P3020470" class_name = "DATASET" call_racf_mock.side_effect = [ - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML, TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, ] with self.assertRaises(AlterOperationError) as exception: @@ -102,7 +131,7 @@ def test_data_set_admin_can_parse_alter_data_set_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -118,43 +147,43 @@ def test_data_set_admin_can_parse_alter_data_set_error_xml( # ============================================================================ # Extract Data Set # ============================================================================ - def test_data_set_admin_can_parse_extract_data_set_base_success_xml( + def test_data_set_admin_can_parse_extract_data_set_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.data_set_admin.extract("ESWIFT.TEST.T1136242.P3020470"), - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_SUCCESS_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_DICTIONARY, ) - def test_data_set_admin_can_parse_extract_data_set_generic_base_success_xml( + def test_data_set_admin_can_parse_extract_data_set_generic_base_only_success_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_SUCCESS_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_XML ) self.assertEqual( self.data_set_admin.extract("ESWIFT.TEST.T1136242.*"), - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_SUCCESS_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_DICTIONARY, ) # Error in environment, ESWIFT.TEST.T1136242.P3020470 already deleted/not added - def test_data_set_admin_can_parse_extract_data_set_base_error_xml( + def test_data_set_admin_can_parse_extract_data_set_base_only_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.return_value = ( - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_XML + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML ) with self.assertRaises(SecurityRequestError) as exception: self.data_set_admin.extract("ESWIFT.TEST.T1136242.P3020470") self.assertEqual( exception.exception.result, - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ERROR_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/group/group_log_samples/add_group_error.log b/tests/group/group_log_samples/add_group_error.log deleted file mode 100644 index 8b14c1a2..00000000 --- a/tests/group/group_log_samples/add_group_error.log +++ /dev/null @@ -1,91 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - GroupAdmin.add() - - -{ - "omvs": { - "omvs:gid": { - "value": "6667", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - GroupAdmin.add() - - - - - - 6667 - - - - - - [pyRACF:Debug] - Result XML - GroupAdmin.add() - - - - - - - 8 - 16 - 8 - ADDGROUP TESTGRP0 - IKJ56702I INVALID GROUP, TESTGRP0 - - - 0 - 0 - 0 - ALTGROUP TESTGRP0 OMVS (GID (6667)) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - GroupAdmin.add() - - -{ - "securityResult": { - "group": { - "name": "TESTGRP0", - "operation": "set", - "requestId": "GroupRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDGROUP TESTGRP0 ", - "messages": [ - "IKJ56702I INVALID GROUP, TESTGRP0" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTGROUP TESTGRP0 OMVS (GID (6667))" - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/group/group_log_samples/add_group_success.log b/tests/group/group_log_samples/add_group_success.log deleted file mode 100644 index 3f0c67d4..00000000 --- a/tests/group/group_log_samples/add_group_success.log +++ /dev/null @@ -1,87 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - GroupAdmin.add() - - -{ - "omvs": { - "omvs:gid": { - "value": "6667", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - GroupAdmin.add() - - - - - - 6667 - - - - - - [pyRACF:Debug] - Result XML - GroupAdmin.add() - - - - - - - 0 - 0 - 0 - ADDGROUP TESTGRP0 - - - 0 - 0 - 0 - ALTGROUP TESTGRP0 OMVS (GID (6667)) - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - GroupAdmin.add() - - -{ - "securityResult": { - "group": { - "name": "TESTGRP0", - "operation": "set", - "requestId": "GroupRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ADDGROUP TESTGRP0 " - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTGROUP TESTGRP0 OMVS (GID (6667))" - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/group/group_log_samples/alter_group_error.log b/tests/group/group_log_samples/alter_group_error.log new file mode 100644 index 00000000..8b1ad45c --- /dev/null +++ b/tests/group/group_log_samples/alter_group_error.log @@ -0,0 +1,243 @@ + + [pyRACF:Debug] + Request Dictionary + GroupAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + GroupAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + GroupAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTGRP TESTGRP0 + INFORMATION FOR GROUP TESTGRP0 + SUPERIOR GROUP=SYS1 OWNER=ESWIFT CREATED=23.150 + NO INSTALLATION DATA + NO MODEL DATA SET + TERMUACC + NO SUBGROUPS + USER(S)= ACCESS= ACCESS COUNT= UNIVERSAL ACCESS= + ESWIFT USE 000000 NONE + CONNECT ATTRIBUTES=SPECIAL + REVOKE DATE=NONE RESUME DATE=NONE + LEONARD USE 000000 NONE + CONNECT ATTRIBUTES=OPERATIONS + REVOKE DATE=NONE RESUME DATE=NONE + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "listdata", + "requestId": "GroupRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTGRP TESTGRP0 ", + "messages": [ + "INFORMATION FOR GROUP TESTGRP0", + " SUPERIOR GROUP=SYS1 OWNER=ESWIFT CREATED=23.150", + " NO INSTALLATION DATA", + " NO MODEL DATA SET", + " TERMUACC", + " NO SUBGROUPS", + " USER(S)= ACCESS= ACCESS COUNT= UNIVERSAL ACCESS=", + " ESWIFT USE 000000 NONE", + " CONNECT ATTRIBUTES=SPECIAL", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LEONARD USE 000000 NONE", + " CONNECT ATTRIBUTES=OPERATIONS", + " REVOKE DATE=NONE RESUME DATE=NONE" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "listdata", + "requestId": "GroupRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTGRP TESTGRP0 ", + "profiles": [ + { + "base": { + "name": "testgrp0", + "superiorGroup": "sys1", + "owner": "eswift", + "created": "5/30/2023", + "installationData": null, + "modelDataSet": null, + "terminalUniversalAccess": true, + "subgroups": [], + "users": [ + { + "userid": "eswift", + "access": "use", + "accessCount": 0, + "universalAccess": null, + "connectAttributes": [ + "special" + ], + "revokeDate": null, + "resumeDate": null + }, + { + "userid": "leonard", + "access": "use", + "accessCount": 0, + "universalAccess": null, + "connectAttributes": [ + "operations" + ], + "revokeDate": null, + "resumeDate": null + } + ] + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + GroupAdmin.alter() + + +{ + "omvs": { + "omvs:gid": { + "value": "3000000000", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + GroupAdmin.alter() + + + + + + 3000000000 + + + + + + [pyRACF:Debug] + Result XML + GroupAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + ALTGROUP TESTGRP0 OMVS (GID (3000000000)) + IKJ56702I INVALID GID, 3000000000 + IKJ56701I MISSING OMVS GID+ + IKJ56701I MISSING OMVS GROUP ID (GID), 1-10 NUMERIC DIGITS + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "set", + "requestId": "GroupRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTGROUP TESTGRP0 OMVS (GID (3000000000))", + "messages": [ + "IKJ56702I INVALID GID, 3000000000", + "IKJ56701I MISSING OMVS GID+", + "IKJ56701I MISSING OMVS GROUP ID (GID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/group/group_log_samples/alter_group_success.log b/tests/group/group_log_samples/alter_group_success.log new file mode 100644 index 00000000..1e1d1365 --- /dev/null +++ b/tests/group/group_log_samples/alter_group_success.log @@ -0,0 +1,235 @@ + + [pyRACF:Debug] + Request Dictionary + GroupAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + GroupAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + GroupAdmin.alter() + + + + + + + 0 + 0 + 0 + LISTGRP TESTGRP0 + INFORMATION FOR GROUP TESTGRP0 + SUPERIOR GROUP=SYS1 OWNER=ESWIFT CREATED=23.150 + NO INSTALLATION DATA + NO MODEL DATA SET + TERMUACC + NO SUBGROUPS + USER(S)= ACCESS= ACCESS COUNT= UNIVERSAL ACCESS= + ESWIFT USE 000000 NONE + CONNECT ATTRIBUTES=SPECIAL + REVOKE DATE=NONE RESUME DATE=NONE + LEONARD USE 000000 NONE + CONNECT ATTRIBUTES=OPERATIONS + REVOKE DATE=NONE RESUME DATE=NONE + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "listdata", + "requestId": "GroupRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTGRP TESTGRP0 ", + "messages": [ + "INFORMATION FOR GROUP TESTGRP0", + " SUPERIOR GROUP=SYS1 OWNER=ESWIFT CREATED=23.150", + " NO INSTALLATION DATA", + " NO MODEL DATA SET", + " TERMUACC", + " NO SUBGROUPS", + " USER(S)= ACCESS= ACCESS COUNT= UNIVERSAL ACCESS=", + " ESWIFT USE 000000 NONE", + " CONNECT ATTRIBUTES=SPECIAL", + " REVOKE DATE=NONE RESUME DATE=NONE", + " LEONARD USE 000000 NONE", + " CONNECT ATTRIBUTES=OPERATIONS", + " REVOKE DATE=NONE RESUME DATE=NONE" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "listdata", + "requestId": "GroupRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTGRP TESTGRP0 ", + "profiles": [ + { + "base": { + "name": "testgrp0", + "superiorGroup": "sys1", + "owner": "eswift", + "created": "5/30/2023", + "installationData": null, + "modelDataSet": null, + "terminalUniversalAccess": true, + "subgroups": [], + "users": [ + { + "userid": "eswift", + "access": "use", + "accessCount": 0, + "universalAccess": null, + "connectAttributes": [ + "special" + ], + "revokeDate": null, + "resumeDate": null + }, + { + "userid": "leonard", + "access": "use", + "accessCount": 0, + "universalAccess": null, + "connectAttributes": [ + "operations" + ], + "revokeDate": null, + "resumeDate": null + } + ] + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + GroupAdmin.alter() + + +{ + "omvs": { + "omvs:gid": { + "value": "1234567", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + GroupAdmin.alter() + + + + + + 1234567 + + + + + + [pyRACF:Debug] + Result XML + GroupAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + ALTGROUP TESTGRP0 OMVS (GID (1234567)) + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + GroupAdmin.alter() + + +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "set", + "requestId": "GroupRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTGROUP TESTGRP0 OMVS (GID (1234567))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/group/group_result_samples/add_group_result_error.json b/tests/group/group_result_samples/add_group_result_error.json index 11d6df12..4df6b394 100644 --- a/tests/group/group_result_samples/add_group_result_error.json +++ b/tests/group/group_result_samples/add_group_result_error.json @@ -1,28 +1,19 @@ { "securityResult": { "group": { - "name": "TESTGRP0", + "name": "TESTGRPP0", "operation": "set", "requestId": "GroupRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "ADDGROUP TESTGRP0 ", - "messages": [ - "IKJ56702I INVALID GROUP, TESTGRP0" - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "ALTGROUP TESTGRP0 OMVS (GID (6667))" - } - ] + "error": { + "errorFunction": 10, + "errorCode": 2000, + "errorReason": 68, + "errorMessage": "Invalid attribute value specified.", + "errorOffset": 149, + "textInError": "name" + } }, - "returnCode": 4, - "reasonCode": 0 + "returnCode": 2000, + "reasonCode": 68 } } \ No newline at end of file diff --git a/tests/group/group_result_samples/add_group_result_error.xml b/tests/group/group_result_samples/add_group_result_error.xml index abb4c9fc..0a0aad6e 100644 --- a/tests/group/group_result_samples/add_group_result_error.xml +++ b/tests/group/group_result_samples/add_group_result_error.xml @@ -1,20 +1,15 @@ - - - 8 - 16 - 8 - ADDGROUP TESTGRP0 - IKJ56702I INVALID GROUP, TESTGRP0 - - - 0 - 0 - 0 - ALTGROUP TESTGRP0 OMVS (GID (6667)) - + + + 10 + 2000 + 68 + Invalid attribute value specified. + 149 + name + - 4 - 0 + 2000 + 68 \ No newline at end of file diff --git a/tests/group/group_result_samples/extract_group_result_base_only_error.json b/tests/group/group_result_samples/extract_group_result_base_only_error.json new file mode 100644 index 00000000..3d696bf3 --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_base_only_error.json @@ -0,0 +1,22 @@ +{ + "securityResult": { + "group": { + "name": "TESTGRP0", + "operation": "listdata", + "requestId": "GroupRequest", + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 4, + "image": "LISTGRP TESTGRP0 ", + "messages": [ + "ICH51003I NAME NOT FOUND IN RACF DATA SET" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/group/group_result_samples/extract_group_result_base_only_error.xml b/tests/group/group_result_samples/extract_group_result_base_only_error.xml new file mode 100644 index 00000000..9cef8fac --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_base_only_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + LISTGRP TESTGRP0 + ICH51003I NAME NOT FOUND IN RACF DATA SET + + + 4 + 0 + \ No newline at end of file diff --git a/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json b/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json new file mode 100644 index 00000000..1ef0740a --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json @@ -0,0 +1,19 @@ +{ + "securityResult": { + "group": { + "name": "TESTGRPP0", + "operation": "listdata", + "requestId": "GroupRequest", + "error": { + "errorFunction": 10, + "errorCode": 2000, + "errorReason": 68, + "errorMessage": "Invalid attribute value specified.", + "errorOffset": 149, + "textInError": "name" + } + }, + "returnCode": 2000, + "reasonCode": 68 + } +} \ No newline at end of file diff --git a/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml b/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml new file mode 100644 index 00000000..ba6b7c61 --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml @@ -0,0 +1,15 @@ + + + + + 10 + 2000 + 68 + Invalid attribute value specified. + 149 + name + + + 2000 + 68 + \ No newline at end of file diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index 9da4f7d6..c22849b1 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -48,6 +48,18 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_JSON = get_sample( "extract_group_result_base_only_success.json" ) +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_ERROR_XML = get_sample( + "extract_group_result_base_only_error.xml" +) +TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_ERROR_JSON = get_sample( + "extract_group_result_base_only_error.json" +) +TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_XML = get_sample( + "extract_group_result_invalid_attribute_error.xml" +) +TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY = get_sample( + "extract_group_result_invalid_attribute_error.json" +) # Delete Group TEST_DELETE_GROUP_RESULT_SUCCESS_XML = get_sample("delete_group_result_success.xml") @@ -92,8 +104,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_GROUP_SUCCESS_LOG = get_sample("add_group_success.log") -TEST_ADD_GROUP_ERROR_LOG = get_sample("add_group_error.log") +TEST_ALTER_GROUP_SUCCESS_LOG = get_sample("alter_group_success.log") +TEST_ALTER_GROUP_ERROR_LOG = get_sample("alter_group_error.log") TEST_EXTRACT_GROUP_BASE_OMVS_SUCCESS_LOG = get_sample( "extract_group_base_omvs_success.log" diff --git a/tests/group/test_group_debug_logging.py b/tests/group/test_group_debug_logging.py index fad5e8f6..d4d63265 100644 --- a/tests/group/test_group_debug_logging.py +++ b/tests/group/test_group_debug_logging.py @@ -24,38 +24,43 @@ class TestGroupDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Group + # Alter Group # ============================================================================ - def test_add_group_request_debug_log_works_on_success( + def test_alter_group_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.group_admin.add( - "TESTGRP0", traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS + self.group_admin.alter( + "TESTGRP0", traits=TestGroupConstants.TEST_ALTER_GROUP_REQUEST_TRAITS ) success_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(success_log, TestGroupConstants.TEST_ADD_GROUP_SUCCESS_LOG) + self.assertEqual(success_log, TestGroupConstants.TEST_ALTER_GROUP_SUCCESS_LOG) - def test_add_group_request_debug_log_works_on_error( + def test_alter_group_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.group_admin.add( - "TESTGRP0", traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS + self.group_admin.alter( + "TESTGRP0", + traits=TestGroupConstants.TEST_ALTER_GROUP_REQUEST_ERROR_TRAITS, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestGroupConstants.TEST_ADD_GROUP_ERROR_LOG) + self.assertEqual(error_log, TestGroupConstants.TEST_ALTER_GROUP_ERROR_LOG) # ============================================================================ # Extract Group diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 0b81ba5c..0dd2760b 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -6,7 +6,12 @@ import __init__ import tests.group.test_group_constants as TestGroupConstants -from pyracf import AlterOperationError, GroupAdmin, SecurityRequestError +from pyracf import ( + AddOperationError, + AlterOperationError, + GroupAdmin, + SecurityRequestError, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -26,9 +31,10 @@ def test_group_admin_can_parse_add_group_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_ERROR_XML, + TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_XML, + ] self.assertEqual( self.group_admin.add( "TESTGRP0", traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS @@ -36,19 +42,43 @@ def test_group_admin_can_parse_add_group_success_xml( TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_DICTIONARY, ) - # Error in environment, TESTGRP0 already added/exists + def test_group_admin_throws_error_on_add_existing_group( + self, + call_racf_mock: Mock, + ): + group_name = "TESTGRP0" + admin_name = "GROUP" + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, + TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AddOperationError) as exception: + self.group_admin.add( + group_name, traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{group_name}' already exists as a {admin_name} profile.", + ) + + # Error in command, TESTGRPP0 is invalid GROUP def test_group_admin_can_parse_add_group_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_XML, + TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.group_admin.add( - "TESTGRP0", traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS + "TESTGRPP0", traits=TestGroupConstants.TEST_ADD_GROUP_REQUEST_TRAITS ) self.assertEqual( exception.exception.result, - TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_DICTIONARY, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/resource/resource_log_samples/add_resource_error.log b/tests/resource/resource_log_samples/add_resource_error.log deleted file mode 100644 index 4fcf03c2..00000000 --- a/tests/resource/resource_log_samples/add_resource_error.log +++ /dev/null @@ -1,107 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - ResourceAdmin.add() - - -{ - "base": { - "base:universal_access": { - "value": "None", - "operation": null - }, - "base:owner": { - "value": "eswift", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - ResourceAdmin.add() - - - - - - None - eswift - - - - - - [pyRACF:Debug] - Result XML - ResourceAdmin.add() - - - - - - - 8 - 16 - 8 - RDEFINE ELIXTEST (TESTING) - IKJ56702I INVALID CLASS, ELIXTEST - IKJ56701I MISSING ENTITY NAME+ - IKJ56701I MISSING NAME OF ENTITY IN SPECIFIED CLASS - - - 8 - 16 - 8 - RALTER ELIXTEST (TESTING) UACC (None) OWNER (eswift) - IKJ56702I INVALID CLASS, ELIXTEST - IKJ56712I INVALID KEYWORD, ) - - - 4 - 0 - - - - [pyRACF:Debug] - Result Dictionary - ResourceAdmin.add() - - -{ - "securityResult": { - "resource": { - "name": "TESTING", - "class": "ELIXTEST", - "operation": "set", - "requestId": "ResourceRequest", - "commands": [ - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "RDEFINE ELIXTEST (TESTING)", - "messages": [ - "IKJ56702I INVALID CLASS, ELIXTEST", - "IKJ56701I MISSING ENTITY NAME+", - "IKJ56701I MISSING NAME OF ENTITY IN SPECIFIED CLASS" - ] - }, - { - "safReturnCode": 8, - "returnCode": 16, - "reasonCode": 8, - "image": "RALTER ELIXTEST (TESTING) UACC (None) OWNER (eswift)", - "messages": [ - "IKJ56702I INVALID CLASS, ELIXTEST", - "IKJ56712I INVALID KEYWORD, )" - ] - } - ] - }, - "returnCode": 4, - "reasonCode": 0 - } -} - diff --git a/tests/resource/resource_log_samples/add_resource_success.log b/tests/resource/resource_log_samples/add_resource_success.log deleted file mode 100644 index 8e8e6856..00000000 --- a/tests/resource/resource_log_samples/add_resource_success.log +++ /dev/null @@ -1,101 +0,0 @@ - - [pyRACF:Debug] - Request Dictionary - ResourceAdmin.add() - - -{ - "base": { - "base:universal_access": { - "value": "None", - "operation": null - }, - "base:owner": { - "value": "eswift", - "operation": null - } - } -} - - - [pyRACF:Debug] - Request XML - ResourceAdmin.add() - - - - - - None - eswift - - - - - - [pyRACF:Debug] - Result XML - ResourceAdmin.add() - - - - - - - 0 - 0 - 0 - RDEFINE ELIJTEST (TESTING) - ICH10006I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE ADDITION(S) UNTIL A SETROPTS REFRESH IS ISSUED. - - - 0 - 0 - 0 - RALTER ELIJTEST (TESTING) UACC (None) OWNER (eswift) - ICH11009I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED. - - - 0 - 0 - - - - [pyRACF:Debug] - Result Dictionary - ResourceAdmin.add() - - -{ - "securityResult": { - "resource": { - "name": "TESTING", - "class": "ELIJTEST", - "operation": "set", - "requestId": "ResourceRequest", - "commands": [ - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "RDEFINE ELIJTEST (TESTING) ", - "messages": [ - "ICH10006I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE ADDITION(S) UNTIL A SETROPTS REFRESH IS ISSUED." - ] - }, - { - "safReturnCode": 0, - "returnCode": 0, - "reasonCode": 0, - "image": "RALTER ELIJTEST (TESTING) UACC (None) OWNER (eswift)", - "messages": [ - "ICH11009I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED." - ] - } - ] - }, - "returnCode": 0, - "reasonCode": 0 - } -} - diff --git a/tests/resource/resource_log_samples/alter_resource_error.log b/tests/resource/resource_log_samples/alter_resource_error.log new file mode 100644 index 00000000..922c6157 --- /dev/null +++ b/tests/resource/resource_log_samples/alter_resource_error.log @@ -0,0 +1,253 @@ + + [pyRACF:Debug] + Request Dictionary + ResourceAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + ResourceAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + ResourceAdmin.alter() + + + + + + + 0 + 0 + 0 + RLIST ELIJTEST (TESTING) + CLASS NAME + ----- ---- + ELIJTEST TESTING + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT READ READ NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "listdata", + "requestId": "ResourceRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "RLIST ELIJTEST (TESTING) ", + "messages": [ + "CLASS NAME", + "----- ----", + "ELIJTEST TESTING", + " ", + "LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING", + "----- -------- ---------------- ----------- -------", + " 00 ESWIFT READ READ NO", + " ", + "INSTALLATION DATA", + "-----------------", + "NONE", + " ", + "APPLICATION DATA", + "----------------", + "NONE", + " ", + "AUDITING", + "--------", + "FAILURES(READ)", + " ", + "NOTIFY", + "------", + "NO USER TO BE NOTIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "listdata", + "requestId": "ResourceRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "RLIST ELIJTEST (TESTING) ", + "profiles": [ + { + "base": { + "class": "elijtest", + "name": "testing", + "level": 0, + "owner": "eswift", + "universalAccess": "read", + "yourAccess": "read", + "warning": null, + "installationData": null, + "applicationData": null, + "auditing": { + "failures": "read" + }, + "notify": null, + "generic": false + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + ResourceAdmin.alter() + + +{ + "base": { + "base:universal_access": { + "value": "ALL", + "operation": null + }, + "base:owner": { + "value": "eswift", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + ResourceAdmin.alter() + + + + + + ALL + eswift + + + + + + [pyRACF:Debug] + Result XML + ResourceAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 8 + 16 + 8 + RALTER ELIJTEST (TESTING) UACC (ALL) OWNER (eswift) + IKJ56702I INVALID UNIVERSAL ACCESS, ALL + IKJ56701I MISSING UNIVERSAL ACCESS+ + IKJ56701I MISSING ALTER, CONTROL, UPDATE, READ, EXECUTE, OR NONE + + + 4 + 0 + + + + [pyRACF:Debug] + Result Dictionary + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "set", + "requestId": "ResourceRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "RALTER ELIJTEST (TESTING) UACC (ALL) OWNER (eswift)", + "messages": [ + "IKJ56702I INVALID UNIVERSAL ACCESS, ALL", + "IKJ56701I MISSING UNIVERSAL ACCESS+", + "IKJ56701I MISSING ALTER, CONTROL, UPDATE, READ, EXECUTE, OR NONE" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} + diff --git a/tests/resource/resource_log_samples/alter_resource_success.log b/tests/resource/resource_log_samples/alter_resource_success.log new file mode 100644 index 00000000..5f5a6f9b --- /dev/null +++ b/tests/resource/resource_log_samples/alter_resource_success.log @@ -0,0 +1,249 @@ + + [pyRACF:Debug] + Request Dictionary + ResourceAdmin.alter() + + +{} + + + [pyRACF:Debug] + Request XML + ResourceAdmin.alter() + + + + + + + + [pyRACF:Debug] + Result XML + ResourceAdmin.alter() + + + + + + + 0 + 0 + 0 + RLIST ELIJTEST (TESTING) + CLASS NAME + ----- ---- + ELIJTEST TESTING + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT READ READ NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "listdata", + "requestId": "ResourceRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "RLIST ELIJTEST (TESTING) ", + "messages": [ + "CLASS NAME", + "----- ----", + "ELIJTEST TESTING", + " ", + "LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING", + "----- -------- ---------------- ----------- -------", + " 00 ESWIFT READ READ NO", + " ", + "INSTALLATION DATA", + "-----------------", + "NONE", + " ", + "APPLICATION DATA", + "----------------", + "NONE", + " ", + "AUDITING", + "--------", + "FAILURES(READ)", + " ", + "NOTIFY", + "------", + "NO USER TO BE NOTIFIED" + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Result Dictionary (Formatted Profile) + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "listdata", + "requestId": "ResourceRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "RLIST ELIJTEST (TESTING) ", + "profiles": [ + { + "base": { + "class": "elijtest", + "name": "testing", + "level": 0, + "owner": "eswift", + "universalAccess": "read", + "yourAccess": "read", + "warning": null, + "installationData": null, + "applicationData": null, + "auditing": { + "failures": "read" + }, + "notify": null, + "generic": false + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + + + [pyRACF:Debug] + Request Dictionary + ResourceAdmin.alter() + + +{ + "base": { + "base:universal_access": { + "value": "Read", + "operation": null + }, + "base:owner": { + "value": "eswift", + "operation": null + } + } +} + + + [pyRACF:Debug] + Request XML + ResourceAdmin.alter() + + + + + + Read + eswift + + + + + + [pyRACF:Debug] + Result XML + ResourceAdmin.alter() + + + + + + Definition exists. Add command skipped due to precheck option + + 0 + 0 + 0 + RALTER ELIJTEST (TESTING) UACC (Read) OWNER (eswift) + ICH11009I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED. + + + 0 + 0 + + + + [pyRACF:Debug] + Result Dictionary + ResourceAdmin.alter() + + +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIJTEST", + "operation": "set", + "requestId": "ResourceRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "RALTER ELIJTEST (TESTING) UACC (Read) OWNER (eswift)", + "messages": [ + "ICH11009I RACLISTED PROFILES FOR ELIJTEST WILL NOT REFLECT THE UPDATE(S) UNTIL A SETROPTS REFRESH IS ISSUED." + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} + diff --git a/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json b/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json new file mode 100644 index 00000000..dde77d51 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json @@ -0,0 +1,25 @@ +{ + "securityResult": { + "resource": { + "name": "TESTING", + "class": "ELIXTEST", + "operation": "listdata", + "requestId": "ResourceRequest", + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "RLIST ELIXTEST (TESTING) ", + "messages": [ + "IKJ56702I INVALID CLASS NAME, ELIXTEST", + "IKJ56701I MISSING ENTITY NAME+", + "IKJ56701I MISSING NAME OF ENTITY TO BE LISTED" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml b/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml new file mode 100644 index 00000000..6851ec10 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml @@ -0,0 +1,16 @@ + + + + + 8 + 16 + 8 + RLIST ELIXTEST (TESTING) + IKJ56702I INVALID CLASS NAME, ELIXTEST + IKJ56701I MISSING ENTITY NAME+ + IKJ56701I MISSING NAME OF ENTITY TO BE LISTED + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index 15538f05..f308e6f4 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -52,6 +52,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_RESOURCE_RESULT_BASE_ERROR_DICTIONARY = get_sample( "extract_resource_result_base_error.json" ) +TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_XML = get_sample( + "extract_resource_result_invalid_class_error.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_DICTIONARY = get_sample( + "extract_resource_result_invalid_class_error.json" +) # Delete Resource TEST_DELETE_RESOURCE_RESULT_SUCCESS_XML = get_sample( @@ -107,8 +113,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Debug Logging # ============================================================================ -TEST_ADD_RESOURCE_SUCCESS_LOG = get_sample("add_resource_success.log") -TEST_ADD_RESOURCE_ERROR_LOG = get_sample("add_resource_error.log") +TEST_ALTER_RESOURCE_SUCCESS_LOG = get_sample("alter_resource_success.log") +TEST_ALTER_RESOURCE_ERROR_LOG = get_sample("alter_resource_error.log") TEST_EXTRACT_RESOURCE_BASE_SUCCESS_LOG = get_sample("extract_resource_base_success.log") TEST_EXTRACT_RESOURCE_BASE_ERROR_LOG = get_sample("extract_resource_base_error.log") diff --git a/tests/resource/test_resource_debug_logging.py b/tests/resource/test_resource_debug_logging.py index 2fac5c60..8342649d 100644 --- a/tests/resource/test_resource_debug_logging.py +++ b/tests/resource/test_resource_debug_logging.py @@ -24,46 +24,48 @@ class TestResourceDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Resource + # Alter Resource # ============================================================================ - def test_add_resource_request_debug_log_works_on_success( + def test_alter_resource_request_debug_log_works_on_success( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.resource_admin.add( + self.resource_admin.alter( "TESTING", "ELIJTEST", - traits=TestResourceConstants.TEST_ADD_RESOURCE_REQUEST_TRAITS, + traits=TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_TRAITS, ) success_log = self.ansi_escape.sub("", stdout.getvalue()) self.assertEqual( - success_log, TestResourceConstants.TEST_ADD_RESOURCE_SUCCESS_LOG + success_log, TestResourceConstants.TEST_ALTER_RESOURCE_SUCCESS_LOG ) - def test_add_resource_request_debug_log_works_on_error( + def test_alter_resource_request_debug_log_works_on_error( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_XML, + ] stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.resource_admin.add( + self.resource_admin.alter( "TESTING", - "ELIXTEST", - traits=TestResourceConstants.TEST_ADD_RESOURCE_REQUEST_ERROR_TRAITS, + "ELIJTEST", + traits=TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_ERROR_TRAITS, ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) - self.assertEqual(error_log, TestResourceConstants.TEST_ADD_RESOURCE_ERROR_LOG) + self.assertEqual(error_log, TestResourceConstants.TEST_ALTER_RESOURCE_ERROR_LOG) # ============================================================================ # Extract Resource diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 7b5bc9b0..624157de 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -6,7 +6,12 @@ import __init__ import tests.resource.test_resource_constants as TestResourceConstants -from pyracf import AlterOperationError, ResourceAdmin, SecurityRequestError +from pyracf import ( + AddOperationError, + AlterOperationError, + ResourceAdmin, + SecurityRequestError, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -26,27 +31,52 @@ def test_resource_admin_can_parse_add_resource_success_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_ERROR_XML, + TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_XML, + ] self.assertEqual( self.resource_admin.add("TESTING", "ELIJTEST"), TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_DICTIONARY, ) + def test_resource_admin_throws_error_on_add_existing_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "TESTING" + class_name = "ELIJTEST" + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, + TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AddOperationError) as exception: + self.resource_admin.add( + profile_name, + class_name, + traits=TestResourceConstants.TEST_ADD_RESOURCE_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' already exists as a profile in the {class_name} class.", + ) + # Error: Invalid Entity Name ELIXTEST def test_resource_admin_can_parse_add_resource_error_xml( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_XML, + TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.resource_admin.add("TESTING", "ELIXTEST") self.assertEqual( exception.exception.result, - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_DICTIONARY, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index b19f165e..8096c33e 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -6,7 +6,12 @@ import __init__ import tests.user.test_user_constants as TestUserConstants -from pyracf import AlterOperationError, SecurityRequestError, UserAdmin +from pyracf import ( + AddOperationError, + AlterOperationError, + SecurityRequestError, + UserAdmin, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -41,6 +46,27 @@ def test_user_admin_can_parse_add_user_success_xml( TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_DICTIONARY, ) + def test_user_admin_throws_error_on_add_existing_user( + self, + call_racf_mock: Mock, + ): + profile_name = "squidwrd" + admin_name = "USER" + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AddOperationError) as exception: + self.user_admin.add( + profile_name, traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Security request made to IRRSMO00 failed." + + "\n\nTarget profile " + + f"'{profile_name}' already exists as a {admin_name} profile.", + ) + # Error in command, SQUIDWARD is invalid USERID def test_user_admin_can_parse_add_user_error_xml( self, From e2ad70288dadbbb821edb5666fde548af8ffb42d Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 26 Oct 2023 15:23:25 -0400 Subject: [PATCH 44/72] Minor Name Changes General_command_classes -> Generic_command_classes set/remove grpacc in connection admin to give/take away grpacc Signed-off-by: Elijah Swift --- pyracf/connection/connection_admin.py | 6 ++++-- pyracf/setropts/setropts_admin.py | 6 +++--- ...ute.xml => connection_give_group_access_attribute.xml} | 0 ...ml => connection_take_away_group_access_attribute.xml} | 0 tests/connection/test_connection_constants.py | 4 ++-- tests/connection/test_connection_setters.py | 8 ++++---- 6 files changed, 13 insertions(+), 11 deletions(-) rename tests/connection/connection_request_samples/{connection_set_group_access_attribute.xml => connection_give_group_access_attribute.xml} (100%) rename tests/connection/connection_request_samples/{connection_remove_group_access_attribute.xml => connection_take_away_group_access_attribute.xml} (100%) diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index b29f8425..c5f33f31 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -96,7 +96,9 @@ def take_away_group_auditor_authority( # ============================================================================ # Group Access # ============================================================================ - def set_group_access_attribute(self, userid: str, group: str) -> Union[dict, bytes]: + def give_group_access_attribute( + self, userid: str, group: str + ) -> Union[dict, bytes]: """ Automatically make group data set profiles that a user creates accessible to all members of the group. @@ -104,7 +106,7 @@ def set_group_access_attribute(self, userid: str, group: str) -> Union[dict, byt result = self.connect(userid, group, {"base:group_access": True}) return self._to_steps(result) - def remove_group_access_attribute( + def take_away_group_access_attribute( self, userid: str, group: str ) -> Union[dict, bytes]: """ diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index d3043a65..92bc7f68 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -32,7 +32,7 @@ def __init__( "base:erase_data_sets_on_delete": "racf:erase", "base:erase_data_sets_on_delete_all": "racf:eraseall", "base:erase_data_sets_on_delete_security_level": "racf:erasesec", - "base:general_command_classes": "racf:gencmd", + "base:generic_command_classes": "racf:gencmd", "base:generic_profile_checking_classes": "racf:generic", "base:generic_profile_sharing_classes": "racf:genlist", "base:generic_owner": "racf:genowner", @@ -210,7 +210,7 @@ def add_generic_command_processing_classes( Add class(es) to the list of classes that have generic profile command processing enabled. """ - result = self.alter(options={"base:general_command_classes": class_names}) + result = self.alter(options={"base:generic_command_classes": class_names}) return self._to_steps(result) def remove_generic_command_processing_classes( @@ -221,7 +221,7 @@ def remove_generic_command_processing_classes( have generic profile command processing enabled. """ result = self.alter( - options={"delete:base:general_command_classes": class_names} + options={"delete:base:generic_command_classes": class_names} ) return self._to_steps(result) diff --git a/tests/connection/connection_request_samples/connection_set_group_access_attribute.xml b/tests/connection/connection_request_samples/connection_give_group_access_attribute.xml similarity index 100% rename from tests/connection/connection_request_samples/connection_set_group_access_attribute.xml rename to tests/connection/connection_request_samples/connection_give_group_access_attribute.xml diff --git a/tests/connection/connection_request_samples/connection_remove_group_access_attribute.xml b/tests/connection/connection_request_samples/connection_take_away_group_access_attribute.xml similarity index 100% rename from tests/connection/connection_request_samples/connection_remove_group_access_attribute.xml rename to tests/connection/connection_request_samples/connection_take_away_group_access_attribute.xml diff --git a/tests/connection/test_connection_constants.py b/tests/connection/test_connection_constants.py index 4f5a34ea..2af94ccf 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -81,10 +81,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "connection_take_away_group_operations_authority.xml" ) TEST_CONNECTION_SET_GROUP_ACCESS_ATTRIBUTE = get_sample( - "connection_set_group_access_attribute.xml" + "connection_give_group_access_attribute.xml" ) TEST_CONNECTION_REMOVE_GROUP_ACCESS_ATTRIBUTE = get_sample( - "connection_remove_group_access_attribute.xml" + "connection_take_away_group_access_attribute.xml" ) # ============================================================================ diff --git a/tests/connection/test_connection_setters.py b/tests/connection/test_connection_setters.py index 2d362f4f..d79607bc 100644 --- a/tests/connection/test_connection_setters.py +++ b/tests/connection/test_connection_setters.py @@ -82,14 +82,14 @@ def test_connection_admin_build_take_away_group_operations_authority_request(sel # ============================================================================ # Group Access Attribute # ============================================================================ - def test_connection_admin_build_set_group_access_attribute_request(self): - result = self.connection_admin.set_group_access_attribute("ESWIFT", "TESTGRP0") + def test_connection_admin_build_give_group_access_attribute_request(self): + result = self.connection_admin.give_group_access_attribute("ESWIFT", "TESTGRP0") self.assertEqual( result, TestConnectionConstants.TEST_CONNECTION_SET_GROUP_ACCESS_ATTRIBUTE ) - def test_connection_admin_build_remove_group_access_attribute(self): - result = self.connection_admin.remove_group_access_attribute( + def test_connection_admin_build_take_away_group_access_attribute(self): + result = self.connection_admin.take_away_group_access_attribute( "ESWIFT", "TESTGRP0" ) self.assertEqual( From c4970171053f5974a3808c495993ba9823554ebf Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 10:55:16 -0400 Subject: [PATCH 45/72] Fixing commented concerns. Signed-off-by: Elijah Swift --- pyracf/__init__.py | 4 +- pyracf/common/add_operation_error.py | 8 ++-- pyracf/common/alter_operation_error.py | 8 ++-- pyracf/common/invalid_segment_name_error.py | 18 --------- pyracf/common/invalid_segment_trait_error.py | 18 --------- pyracf/common/security_admin.py | 32 +++++++-------- pyracf/common/security_request_error.py | 6 ++- pyracf/common/segment_error.py | 17 ++++++++ pyracf/common/segment_trait_error.py | 16 ++++++++ pyracf/data_set/data_set_admin.py | 6 +-- pyracf/group/group_admin.py | 6 +-- pyracf/resource/resource_admin.py | 2 +- pyracf/setropts/setropts_admin.py | 40 +++++++++---------- pyracf/user/user_admin.py | 6 +-- tests/access/test_access_constants.py | 4 +- tests/access/test_access_debug_logging.py | 2 +- tests/access/test_access_result_parser.py | 2 +- tests/connection/test_connection_constants.py | 4 +- .../test_connection_debug_logging.py | 2 +- .../test_connection_result_parser.py | 2 +- tests/data_set/test_data_set_result_parser.py | 8 ++-- tests/group/test_group_result_parser.py | 6 +-- tests/resource/test_resource_result_parser.py | 4 +- tests/user/test_user_constants.py | 4 +- tests/user/test_user_request_builder.py | 29 +++++++------- tests/user/test_user_result_parser.py | 6 +-- 26 files changed, 126 insertions(+), 134 deletions(-) delete mode 100644 pyracf/common/invalid_segment_name_error.py delete mode 100644 pyracf/common/invalid_segment_trait_error.py create mode 100644 pyracf/common/segment_error.py create mode 100644 pyracf/common/segment_trait_error.py diff --git a/pyracf/__init__.py b/pyracf/__init__.py index 7c686b12..9254e04e 100644 --- a/pyracf/__init__.py +++ b/pyracf/__init__.py @@ -2,9 +2,9 @@ from .access.access_admin import AccessAdmin from .common.add_operation_error import AddOperationError from .common.alter_operation_error import AlterOperationError -from .common.invalid_segment_name_error import InvalidSegmentNameError -from .common.invalid_segment_trait_error import InvalidSegmentTraitError from .common.security_request_error import SecurityRequestError +from .common.segment_error import SegmentError +from .common.segment_trait_error import SegmentTraitError from .connection.connection_admin import ConnectionAdmin from .data_set.data_set_admin import DataSetAdmin from .group.group_admin import GroupAdmin diff --git a/pyracf/common/add_operation_error.py b/pyracf/common/add_operation_error.py index 57d7db15..4d1a1f4f 100644 --- a/pyracf/common/add_operation_error.py +++ b/pyracf/common/add_operation_error.py @@ -3,21 +3,21 @@ class AddOperationError(Exception): """ - Raised when a profile passed into an Add is successfully extracted. + Raised when a profile cannot be added because it already exists. """ def __init__(self, profile_name: str, class_name: str) -> None: self.message = "Security request made to IRRSMO00 failed." - admin_types = ["USER", "GROUP", "DATASET"] + admin_types = ["user", "group", "dataSet"] if class_name not in admin_types: self.message += ( "\n\nTarget profile " - + f"'{profile_name}' already exists as a profile in the {class_name} class." + + f"'{profile_name}' already exists as a profile in the '{class_name}' class." ) else: self.message += ( "\n\nTarget profile " - + f"'{profile_name}' already exists as a {class_name} profile." + + f"'{profile_name}' already exists as a '{class_name}' profile." ) def __str__(self) -> str: diff --git a/pyracf/common/alter_operation_error.py b/pyracf/common/alter_operation_error.py index 6f046938..67495833 100644 --- a/pyracf/common/alter_operation_error.py +++ b/pyracf/common/alter_operation_error.py @@ -3,21 +3,21 @@ class AlterOperationError(Exception): """ - Raised when a profile passed into an Alter is not successfully extracted. + Raised when a profile cannot be altered because it does not exist. """ def __init__(self, profile_name: str, class_name: str) -> None: self.message = "Security request made to IRRSMO00 failed." - admin_types = ["USER", "GROUP", "DATASET"] + admin_types = ["user", "group", "dataSet"] if class_name not in admin_types: self.message += ( "\n\nTarget profile " - + f"'{profile_name}' does not exist as a profile in the {class_name} class." + + f"'{profile_name}' does not exist as a profile in the '{class_name}' class." ) else: self.message += ( "\n\nTarget profile " - + f"'{profile_name}' does not exist as a {class_name} profile." + + f"'{profile_name}' does not exist as a '{class_name}' profile." ) def __str__(self) -> str: diff --git a/pyracf/common/invalid_segment_name_error.py b/pyracf/common/invalid_segment_name_error.py deleted file mode 100644 index e8d08e69..00000000 --- a/pyracf/common/invalid_segment_name_error.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Exception to use when the user passes invalid segment name(s) on an extract request.""" - - -class InvalidSegmentNameError(Exception): - """ - Raised when a user passes an invalid segment name on an extract request. - """ - - def __init__(self, invalid_segments: list) -> None: - self.message = "Building of Security Request failed.\n\n" - for segment in invalid_segments: - self.message += ( - "Could not find " - + f"'{segment}' in valid segments for the requested operation.\n" - ) - - def __str__(self) -> str: - return self.message diff --git a/pyracf/common/invalid_segment_trait_error.py b/pyracf/common/invalid_segment_trait_error.py deleted file mode 100644 index be9d92ba..00000000 --- a/pyracf/common/invalid_segment_trait_error.py +++ /dev/null @@ -1,18 +0,0 @@ -"""Exception to use when the user passes invalid segment-trait(s) in the traits dictionary.""" - - -class InvalidSegmentTraitError(Exception): - """ - Raised when a user passes an invalid segment-trait combination in the traits dictionary. - """ - - def __init__(self, invalid_traits: list) -> None: - self.message = "Building of Security Request failed.\n\n" - for trait in invalid_traits: - self.message += ( - "Could not find " - + f"'{trait}' in valid segment traits for the requested operation.\n" - ) - - def __str__(self) -> str: - return self.message diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index cdc7a13b..8ff40445 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -5,13 +5,13 @@ from datetime import datetime from typing import Any, List, Tuple, Union -from .invalid_segment_name_error import InvalidSegmentNameError -from .invalid_segment_trait_error import InvalidSegmentTraitError from .irrsmo00 import IRRSMO00 from .logger import Logger from .security_request import SecurityRequest from .security_request_error import SecurityRequestError from .security_result import SecurityResult +from .segment_error import SegmentError +from .segment_trait_error import SegmentTraitError class SecurityAdmin: @@ -66,7 +66,7 @@ def __init__( "base:passphrase": "racf:phrase", } self.__irrsmo00 = IRRSMO00() - self.__profile_type = profile_type + self._profile_type = profile_type self._segment_traits = {} # used to preserve segment traits for debug logging. self.__preserved_segment_traits = {} @@ -262,21 +262,20 @@ def __validate_and_add_trait( def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: """Build segment dictionaries for profile extract.""" - invalid_segments = [] + bad_segments = [] for segment in segments: if segment in self._valid_segment_traits: self._segment_traits[segment] = True else: - invalid_segments.append(segment) - - if invalid_segments: - raise InvalidSegmentNameError(invalid_segments) + bad_segments.append(segment) + if bad_segments: + raise SegmentError(bad_segments, self._profile_type) # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits def _build_segment_dictionaries(self, traits: dict) -> None: """Build segemnt dictionaries for each segment.""" - invalid_traits = [] + bad_traits = [] for trait in traits: trait_valid = False for segment in self._valid_segment_traits: @@ -286,10 +285,9 @@ def _build_segment_dictionaries(self, traits: dict) -> None: if trait_valid: break if not trait_valid: - invalid_traits.append(trait) - - if invalid_traits: - raise InvalidSegmentTraitError(invalid_traits) + bad_traits.append(trait) + if bad_traits: + raise SegmentTraitError(bad_traits, self._profile_type) # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits @@ -325,7 +323,7 @@ def _get_profile( if self._generate_requests_only: # Allows this function to work with "self._generate_requests_only" mode. return result - return result["securityResult"][self.__profile_type]["commands"][0]["profiles"][ + return result["securityResult"][self._profile_type]["commands"][0]["profiles"][ index ] @@ -373,15 +371,15 @@ def _format_profile_generic(self, messages: str) -> None: current_segment = messages[i].split()[0].lower() profile[current_segment] = {} i += 2 - if self.__profile_type in ("dataSet", "resource"): + if self._profile_type in ("dataSet", "resource"): i = self.__format_data_set_generic_profile_data( messages, profile, current_segment, i ) - if self.__profile_type == "user": + if self._profile_type == "user": i = self.__format_user_profile_data( messages, profile, current_segment, i ) - if self.__profile_type == "group": + if self._profile_type == "group": i = self.__format_group_profile_data( messages, profile, current_segment, i ) diff --git a/pyracf/common/security_request_error.py b/pyracf/common/security_request_error.py index 97e61b7a..6a20bbeb 100644 --- a/pyracf/common/security_request_error.py +++ b/pyracf/common/security_request_error.py @@ -18,14 +18,16 @@ def __init__(self, result: dict) -> None: def __str__(self) -> str: return self.message - def scan_for_error(self, security_definition_tag: str, error_id: str): + def contains_error_message( + self, security_definition_tag: str, error_message_id: str + ): commands = self.result["securityResult"][security_definition_tag].get( "commands" ) if not isinstance(commands, list): return False messages = commands[0].get("messages", []) - if error_id in "".join(messages): + if error_message_id in "".join(messages): return True else: return False diff --git a/pyracf/common/segment_error.py b/pyracf/common/segment_error.py new file mode 100644 index 00000000..4c2a11e3 --- /dev/null +++ b/pyracf/common/segment_error.py @@ -0,0 +1,17 @@ +"""Exception to use when the user passes bad segment name(s) on an extract request.""" + + +class SegmentError(Exception): + """ + Raised when a user passes a bad segment name on an extract request. + """ + + def __init__(self, invalid_segments: list, profile_type: str) -> None: + self.message = "Unable to build Security Request.\n\n" + for segment in invalid_segments: + self.message += ( + f"'{segment}' is not a valid segment for '{profile_type}'.\n" + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/common/segment_trait_error.py b/pyracf/common/segment_trait_error.py new file mode 100644 index 00000000..23d713e6 --- /dev/null +++ b/pyracf/common/segment_trait_error.py @@ -0,0 +1,16 @@ +"""Exception to use when the user passes bad segment-trait name(s) on an add/alter request.""" + + +class SegmentTraitError(Exception): + """ + Raised when a user passes an invalid segment-trait combination in the traits dictionary. + """ + + def __init__(self, invalid_traits: list, profile_type: str) -> None: + self.message = "Unable to build Security Request.\n\n" + for trait in invalid_traits: + self.message += f"'{trait}' is not a valid segment-trait " + self.message += f"combination for '{profile_type}'.\n" + + def __str__(self) -> str: + return self.message diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 1610617e..b5ab7eec 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -113,13 +113,13 @@ def add( try: self.extract(data_set, volume=volume, generic=generic) except SecurityRequestError as exception: - if not exception.scan_for_error("dataSet", "ICH35003I"): + if not exception.contains_error_message(self._profile_type, "ICH35003I"): raise exception self._build_segment_dictionaries(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request) return self._make_request(data_set_request) - raise AddOperationError(data_set, "DATASET") + raise AddOperationError(data_set, self._profile_type) def alter( self, @@ -131,7 +131,7 @@ def alter( try: self.extract(data_set) except SecurityRequestError: - raise AlterOperationError(data_set, "DATASET") + raise AlterOperationError(data_set, self._profile_type) """Alter an existing data set profile.""" self._build_segment_dictionaries(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index fde464f3..f144ce7f 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -130,20 +130,20 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: try: self.extract(group) except SecurityRequestError as exception: - if not exception.scan_for_error("group", "ICH51003I"): + if not exception.contains_error_message(self._profile_type, "ICH51003I"): raise exception self._build_segment_dictionaries(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request) return self._make_request(group_request) - raise AddOperationError(group, "GROUP") + raise AddOperationError(group, self._profile_type) def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" try: self.extract(group) except SecurityRequestError: - raise AlterOperationError(group, "GROUP") + raise AlterOperationError(group, self._profile_type) self._build_segment_dictionaries(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 59c388da..619ca26e 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -231,7 +231,7 @@ def add( try: self.extract(resource, class_name) except SecurityRequestError as exception: - if not exception.scan_for_error("resource", "ICH13003I"): + if not exception.contains_error_message(self._profile_type, "ICH13003I"): raise exception self._build_segment_dictionaries(traits) profile_request = ResourceRequest(resource, class_name, "set") diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 92bc7f68..19597907 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -51,8 +51,8 @@ def __init__( "base:list": "racf:list", "base:audit_log_always_classes": "racf:logalwys", "base:audit_log_default_classes": "racf:logdeflt", - "base:audit_log_failure_classesses": "racf:logfail", - "base:audit_log_never_classesse": "racf:lognever", + "base:audit_log_failure_classes": "racf:logfail", + "base:audit_log_never_classes": "racf:lognever", "base:audit_log_success_classes": "racf:logsucc", "base:min_password_change_interval": "racf:minchang", "base:mixed_case_password_support": "racf:mixdcase", @@ -124,7 +124,7 @@ def get_password_rules(self) -> Union[dict, bytes]: # ============================================================================ # Raclist Refresh # ============================================================================ - def refresh_raclist(self, class_names: Union[List[str], str]) -> Union[dict, bytes]: + def refresh_raclist(self, class_names: Union[str, List[str]]) -> Union[dict, bytes]: """Refresh raclist.""" result = self.alter(options={"base:raclist": class_names, "base:refresh": True}) return self._to_steps(result) @@ -148,14 +148,14 @@ def get_class_attributes(self, class_name: str) -> Union[list, bytes]: # Audit Classes # ============================================================================ def add_audit_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Add class(es) to list of classes that RACF performs auditing for.""" result = self.alter(options={"base:audit_classes": class_names}) return self._to_steps(result) def remove_audit_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Remove class(es) from the list of classes that RACF performs auditing for.""" result = self.alter(options={"delete:base:audit_classes": class_names}) @@ -165,7 +165,7 @@ def remove_audit_classes( # Active Classes # ============================================================================ def add_active_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Add class(es) to the list of classes that RACF performs access authorization checking for. @@ -174,7 +174,7 @@ def add_active_classes( return self._to_steps(result) def remove_active_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Remove class(es) from the list of classes that @@ -187,14 +187,14 @@ def remove_active_classes( # Statistics Classes # ============================================================================ def add_statistics_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Add class(es) to the list of classes that RACF collects statistics for.""" result = self.alter(options={"base:statistics_classes": class_names}) return self._to_steps(result) def remove_statistics_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Remove class(es) from the list of classes that RACF collects statistics for.""" result = self.alter(options={"delete:base:statistics_classes": class_names}) @@ -204,7 +204,7 @@ def remove_statistics_classes( # Generic Command Processing Classes # ============================================================================ def add_generic_command_processing_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Add class(es) to the list of classes that have @@ -214,7 +214,7 @@ def add_generic_command_processing_classes( return self._to_steps(result) def remove_generic_command_processing_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Remove class(es) from the list of classes that @@ -229,7 +229,7 @@ def remove_generic_command_processing_classes( # Generic Profile Checking Classes # ============================================================================ def add_generic_profile_checking_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Add class(es) to the list of classes that have generic profile checking enabled.""" result = self.alter( @@ -238,7 +238,7 @@ def add_generic_profile_checking_classes( return self._to_steps(result) def remove_generic_profile_checking_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Remove class(es) from the list of classes that have generic profile checking enabled.""" result = self.alter( @@ -250,7 +250,7 @@ def remove_generic_profile_checking_classes( # Generic Profile Sharing Classes # ============================================================================ def add_generic_profile_sharing_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Add class(es) to the list of classes that are eligible for @@ -262,7 +262,7 @@ def add_generic_profile_sharing_classes( return self._to_steps(result) def remove_generic_profile_sharing_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Remove class(es) from the list of classes that are eligible @@ -277,13 +277,13 @@ def remove_generic_profile_sharing_classes( # Global Access Classes # ============================================================================ def add_global_access_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Add class(es) to the list of classes eligible for global access checking.""" return self.alter(options={"base:global_access_classes": class_names}) def remove_global_access_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Remove class(es) from the list of classes eligible for global access checking.""" result = self.alter(options={"delete:base:global_access_classes": class_names}) @@ -293,14 +293,14 @@ def remove_global_access_classes( # Raclist Classes # ============================================================================ def add_raclist_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """Add class(es) to list of classes that have in-storage profile sharing activated.""" result = self.alter(options={"base:raclist": class_names}) return self._to_steps(result) def remove_raclist_classes( - self, class_names: Union[List[str], str] + self, class_names: Union[str, List[str]] ) -> Union[dict, bytes]: """ Remove class(es) from the list of classes that have in-storage profile sharing activated. @@ -622,7 +622,7 @@ def __to_list(self, value_raw: str, n: int = 1) -> List[str]: ] def __add_classes_list(self, profile: dict, class_key: str, value_raw: str) -> None: - """Add a class list to profile""" + """Add a class list to profile.""" if "classes" not in profile: profile["classes"] = {} class_key = class_key.replace("Classes", "") diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index 8db20d69..a126c58e 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -776,13 +776,13 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: try: self.extract(userid) except SecurityRequestError as exception: - if not exception.scan_for_error("user", "ICH30001I"): + if not exception.contains_error_message(self._profile_type, "ICH30001I"): raise exception self._build_segment_dictionaries(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request) return self._make_request(user_request) - raise AddOperationError(userid, "USER") + raise AddOperationError(userid, self._profile_type) def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: """Alter an existing user.""" @@ -794,7 +794,7 @@ def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: try: self.extract(userid) except SecurityRequestError: - raise AlterOperationError(userid, "USER") + raise AlterOperationError(userid, self._profile_type) self._build_segment_dictionaries(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) diff --git a/tests/access/test_access_constants.py b/tests/access/test_access_constants.py index d05d1774..d21117d0 100644 --- a/tests/access/test_access_constants.py +++ b/tests/access/test_access_constants.py @@ -15,7 +15,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Access Administration Result Sample Data # ============================================================================ -# Alter Access +# Permit Access TEST_PERMIT_ACCESS_RESULT_SUCCESS_XML = get_sample("permit_access_result_success.xml") TEST_PERMIT_ACCESS_RESULT_SUCCESS_DICTIONARY = get_sample( "permit_access_result_success.json" @@ -40,7 +40,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Access Administration Request Sample Data # ============================================================================ -# Alter Access +# Permit Access TEST_PERMIT_ACCESS_REQUEST_XML = get_sample("permit_access_request.xml") # Delete Access diff --git a/tests/access/test_access_debug_logging.py b/tests/access/test_access_debug_logging.py index 89f25964..8f70e86b 100644 --- a/tests/access/test_access_debug_logging.py +++ b/tests/access/test_access_debug_logging.py @@ -24,7 +24,7 @@ class TestAccessDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Alter Access + # Permit Access # ============================================================================ def test_permit_access_request_debug_log_works_on_success( self, diff --git a/tests/access/test_access_result_parser.py b/tests/access/test_access_result_parser.py index f81c29ca..b8d15926 100644 --- a/tests/access/test_access_result_parser.py +++ b/tests/access/test_access_result_parser.py @@ -20,7 +20,7 @@ class TestAccessResultParser(unittest.TestCase): access_admin = AccessAdmin() # ============================================================================ - # Alter Access + # Permit Access # ============================================================================ def test_access_admin_can_parse_permit_access_success_xml( self, diff --git a/tests/connection/test_connection_constants.py b/tests/connection/test_connection_constants.py index 2af94ccf..ca1910af 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -15,7 +15,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Connection Administration Result Sample Data # ============================================================================ -# Alter Connection +# Connect Connection TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML = get_sample( "connect_connection_result_success.xml" ) @@ -48,7 +48,7 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Connection Administration Request Sample Data # ============================================================================ -# Alter Connection +# Connect Connection TEST_CONNECT_CONNECTION_REQUEST_XML = get_sample("connect_connection_request.xml") TEST_CONNECT_CONNECTION_REQUEST_TRAITS = { "base:operations": False, diff --git a/tests/connection/test_connection_debug_logging.py b/tests/connection/test_connection_debug_logging.py index 7fd94a08..7adabd20 100644 --- a/tests/connection/test_connection_debug_logging.py +++ b/tests/connection/test_connection_debug_logging.py @@ -24,7 +24,7 @@ class TestConnectionDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Alter Connection + # Connect Connection # ============================================================================ def test_connect_connection_request_debug_log_works_on_success( self, diff --git a/tests/connection/test_connection_result_parser.py b/tests/connection/test_connection_result_parser.py index 1a99f1c3..dcd724a2 100644 --- a/tests/connection/test_connection_result_parser.py +++ b/tests/connection/test_connection_result_parser.py @@ -20,7 +20,7 @@ class TestConnectionResultParser(unittest.TestCase): connection_admin = ConnectionAdmin() # ============================================================================ - # Alter Connection + # Connect Connection # ============================================================================ def test_connection_admin_can_parse_connect_connection_success_xml( self, diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 48aaca27..9f956397 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -48,7 +48,6 @@ def test_data_set_admin_thows_error_on_add_existing_data_set_profile( call_racf_mock: Mock, ): profile_name = "ESWIFT.TEST.T1136242.P3020470" - class_name = "DATASET" call_racf_mock.side_effect = [ TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML, TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML, @@ -62,7 +61,8 @@ def test_data_set_admin_thows_error_on_add_existing_data_set_profile( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' already exists as a {class_name} profile.", + + f"'{profile_name}' already exists as a " + + f"'{self.data_set_admin._profile_type}' profile.", ) # Error in command, ESWIFTTESTT1136242P3020470 is not a valid DATASET @@ -108,7 +108,6 @@ def test_data_set_admin_thows_error_on_alter_new_data_set_profile( call_racf_mock: Mock, ): profile_name = "ESWIFT.TEST.T1136242.P3020470" - class_name = "DATASET" call_racf_mock.side_effect = [ TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_XML, TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, @@ -122,7 +121,8 @@ def test_data_set_admin_thows_error_on_alter_new_data_set_profile( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' does not exist as a {class_name} profile.", + + f"'{profile_name}' does not exist as a " + + f"'{self.data_set_admin._profile_type}' profile.", ) # Error in environment, ESWIFT.TEST.T1136242.P3020470 data set does not exist diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 0dd2760b..7ac63b95 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -47,7 +47,6 @@ def test_group_admin_throws_error_on_add_existing_group( call_racf_mock: Mock, ): group_name = "TESTGRP0" - admin_name = "GROUP" call_racf_mock.side_effect = [ TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, TestGroupConstants.TEST_ADD_GROUP_RESULT_SUCCESS_XML, @@ -60,7 +59,7 @@ def test_group_admin_throws_error_on_add_existing_group( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{group_name}' already exists as a {admin_name} profile.", + + f"'{group_name}' already exists as a '{self.group_admin._profile_type}' profile.", ) # Error in command, TESTGRPP0 is invalid GROUP @@ -104,7 +103,6 @@ def test_group_admin_throws_error_on_alter_new_group( call_racf_mock: Mock, ): group_name = "TESTGRP0" - admin_name = "GROUP" call_racf_mock.side_effect = [ TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_ERROR_XML, TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, @@ -117,7 +115,7 @@ def test_group_admin_throws_error_on_alter_new_group( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{group_name}' does not exist as a {admin_name} profile.", + + f"'{group_name}' does not exist as a '{self.group_admin._profile_type}' profile.", ) # Error: invalid gid "3000000000" diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 624157de..632e44b6 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -60,7 +60,7 @@ def test_resource_admin_throws_error_on_add_existing_profile( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' already exists as a profile in the {class_name} class.", + + f"'{profile_name}' already exists as a profile in the '{class_name}' class.", ) # Error: Invalid Entity Name ELIXTEST @@ -119,7 +119,7 @@ def test_resource_admin_throws_error_on_alter_new_profile( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' does not exist as a profile in the {class_name} class.", + + f"'{profile_name}' does not exist as a profile in the '{class_name}' class.", ) # Error: Invalid Universal Access ALL diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index fedc6e55..3bfa719c 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -169,8 +169,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "tso:user_data": "ABCD", "tso:data_set_allocation_unit": "SYSDA", } -TEST_ADD_USER_REQUEST_INVALID_TRAITS = dict(TEST_ADD_USER_REQUEST_TRAITS) -TEST_ADD_USER_REQUEST_INVALID_TRAITS["omvs:invalid_trait"] = "TESTING VALUE" +TEST_ADD_USER_REQUEST_BAD_TRAITS = dict(TEST_ADD_USER_REQUEST_TRAITS) +TEST_ADD_USER_REQUEST_BAD_TRAITS["omvs:bad_trait"] = "TESTING VALUE" # Alter User TEST_ALTER_USER_REQUEST_XML = get_sample("alter_user_request.xml") diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index f4035576..f3d88ee5 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -6,7 +6,7 @@ import __init__ import tests.user.test_user_constants as TestUserConstants -from pyracf import InvalidSegmentNameError, InvalidSegmentTraitError, UserAdmin +from pyracf import SegmentError, SegmentTraitError, UserAdmin from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -124,32 +124,31 @@ def test_user_admin_build_alter_request_update_existing_segment_traits(self): # ============================================================================ # Request Builder Errors # ============================================================================ - def test_user_admin_build_add_request_with_invalid_segment_traits(self): - invalid_trait = "omvs:invalid_trait" + def test_user_admin_build_add_request_with_bad_segment_traits(self): + bad_trait = "omvs:bad_trait" user_admin = UserAdmin( generate_requests_only=True, ) - with self.assertRaises(InvalidSegmentTraitError) as exception: + with self.assertRaises(SegmentTraitError) as exception: user_admin.add( - "squidwrd", TestUserConstants.TEST_ADD_USER_REQUEST_INVALID_TRAITS + "squidwrd", TestUserConstants.TEST_ADD_USER_REQUEST_BAD_TRAITS ) self.assertEqual( exception.exception.message, - "Building of Security Request failed.\n\n" - + "Could not find " - + f"'{invalid_trait}' in valid segment traits for the requested operation.\n", + "Unable to build Security Request.\n\n" + + f"'{bad_trait}' is not a valid segment-trait " + + f"combination for '{self.user_admin._profile_type}'.\n", ) - def test_user_admin_build_extract_request_with_invalid_segment_name(self): - invalid_segment = "test_segment" + def test_user_admin_build_extract_request_with_bad_segment_name(self): + bad_segment = "bad_segment" user_admin = UserAdmin( generate_requests_only=True, ) - with self.assertRaises(InvalidSegmentNameError) as exception: - user_admin.extract("squidwrd", {invalid_segment: True}) + with self.assertRaises(SegmentError) as exception: + user_admin.extract("squidwrd", segments=[bad_segment]) self.assertEqual( exception.exception.message, - "Building of Security Request failed.\n\n" - + "Could not find " - + f"'{invalid_segment}' in valid segments for the requested operation.\n", + "Unable to build Security Request.\n\n" + + f"'{bad_segment}' is not a valid segment for '{self.user_admin._profile_type}'.\n", ) diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 8096c33e..dc02d611 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -51,7 +51,6 @@ def test_user_admin_throws_error_on_add_existing_user( call_racf_mock: Mock, ): profile_name = "squidwrd" - admin_name = "USER" call_racf_mock.side_effect = [ TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_XML, @@ -64,7 +63,7 @@ def test_user_admin_throws_error_on_add_existing_user( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' already exists as a {admin_name} profile.", + + f"'{profile_name}' already exists as a '{self.user_admin._profile_type}' profile.", ) # Error in command, SQUIDWARD is invalid USERID @@ -109,7 +108,6 @@ def test_user_admin_throws_error_on_alter_new_user( call_racf_mock: Mock, ): profile_name = "squidwrd" - admin_name = "USER" call_racf_mock.side_effect = [ TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_ERROR_XML, TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, @@ -122,7 +120,7 @@ def test_user_admin_throws_error_on_alter_new_user( exception.exception.message, "Security request made to IRRSMO00 failed." + "\n\nTarget profile " - + f"'{profile_name}' does not exist as a {admin_name} profile.", + + f"'{profile_name}' does not exist as a '{self.user_admin._profile_type}' profile.", ) # Error: invalid uid '90000000000' From daf84ab4daf92e968c0fbe9939f7f2bc111c9ca9 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 11:02:09 -0400 Subject: [PATCH 46/72] Change references to invalid Signed-off-by: Elijah Swift --- pyracf/common/segment_error.py | 6 +++--- pyracf/common/segment_trait_error.py | 8 ++++---- tests/user/test_user_request_builder.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyracf/common/segment_error.py b/pyracf/common/segment_error.py index 4c2a11e3..33d6f667 100644 --- a/pyracf/common/segment_error.py +++ b/pyracf/common/segment_error.py @@ -6,11 +6,11 @@ class SegmentError(Exception): Raised when a user passes a bad segment name on an extract request. """ - def __init__(self, invalid_segments: list, profile_type: str) -> None: + def __init__(self, bad_segments: list, profile_type: str) -> None: self.message = "Unable to build Security Request.\n\n" - for segment in invalid_segments: + for segment in bad_segments: self.message += ( - f"'{segment}' is not a valid segment for '{profile_type}'.\n" + f"'{segment}' is not a known segment for '{profile_type}'.\n" ) def __str__(self) -> str: diff --git a/pyracf/common/segment_trait_error.py b/pyracf/common/segment_trait_error.py index 23d713e6..3f23f8bc 100644 --- a/pyracf/common/segment_trait_error.py +++ b/pyracf/common/segment_trait_error.py @@ -3,13 +3,13 @@ class SegmentTraitError(Exception): """ - Raised when a user passes an invalid segment-trait combination in the traits dictionary. + Raised when a user passes a bad segment-trait combination in the traits dictionary. """ - def __init__(self, invalid_traits: list, profile_type: str) -> None: + def __init__(self, bad_traits: list, profile_type: str) -> None: self.message = "Unable to build Security Request.\n\n" - for trait in invalid_traits: - self.message += f"'{trait}' is not a valid segment-trait " + for trait in bad_traits: + self.message += f"'{trait}' is not a known segment-trait " self.message += f"combination for '{profile_type}'.\n" def __str__(self) -> str: diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index f3d88ee5..282d773c 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -136,7 +136,7 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): self.assertEqual( exception.exception.message, "Unable to build Security Request.\n\n" - + f"'{bad_trait}' is not a valid segment-trait " + + f"'{bad_trait}' is not a known segment-trait " + f"combination for '{self.user_admin._profile_type}'.\n", ) @@ -150,5 +150,5 @@ def test_user_admin_build_extract_request_with_bad_segment_name(self): self.assertEqual( exception.exception.message, "Unable to build Security Request.\n\n" - + f"'{bad_segment}' is not a valid segment for '{self.user_admin._profile_type}'.\n", + + f"'{bad_segment}' is not a known segment for '{self.user_admin._profile_type}'.\n", ) From db9650f6a8202549876aa2aa7844fc8a1b2f1917 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 11:45:36 -0400 Subject: [PATCH 47/72] Remove more invalid references Signed-off-by: Elijah Swift --- pyracf/common/segment_trait_error.py | 6 ++++-- ...act_data_set_result_bad_attribute_error.json} | 0 ...ract_data_set_result_bad_attribute_error.xml} | 0 tests/data_set/test_data_set_constants.py | 8 ++++---- tests/data_set/test_data_set_result_parser.py | 4 ++-- ...xtract_group_result_bad_attribute_error.json} | 0 ...extract_group_result_bad_attribute_error.xml} | 0 tests/group/test_group_constants.py | 8 ++++---- tests/group/test_group_result_parser.py | 8 ++++---- ...extract_resource_result_bad_class_error.json} | 0 ... extract_resource_result_bad_class_error.xml} | 0 tests/resource/test_resource_constants.py | 8 ++++---- tests/resource/test_resource_result_parser.py | 8 ++++---- tests/user/test_user_constants.py | 8 ++++---- tests/user/test_user_result_parser.py | 16 ++++++++-------- ...extract_user_result_bad_attribute_error.json} | 0 ... extract_user_result_bad_attribute_error.xml} | 0 17 files changed, 38 insertions(+), 36 deletions(-) rename tests/data_set/data_set_result_samples/{extract_data_set_result_invalid_attribute_error.json => extract_data_set_result_bad_attribute_error.json} (100%) rename tests/data_set/data_set_result_samples/{extract_data_set_result_invalid_attribute_error.xml => extract_data_set_result_bad_attribute_error.xml} (100%) rename tests/group/group_result_samples/{extract_group_result_invalid_attribute_error.json => extract_group_result_bad_attribute_error.json} (100%) rename tests/group/group_result_samples/{extract_group_result_invalid_attribute_error.xml => extract_group_result_bad_attribute_error.xml} (100%) rename tests/resource/resource_result_samples/{extract_resource_result_invalid_class_error.json => extract_resource_result_bad_class_error.json} (100%) rename tests/resource/resource_result_samples/{extract_resource_result_invalid_class_error.xml => extract_resource_result_bad_class_error.xml} (100%) rename tests/user/user_result_samples/{extract_user_result_invalid_attribute_error.json => extract_user_result_bad_attribute_error.json} (100%) rename tests/user/user_result_samples/{extract_user_result_invalid_attribute_error.xml => extract_user_result_bad_attribute_error.xml} (100%) diff --git a/pyracf/common/segment_trait_error.py b/pyracf/common/segment_trait_error.py index 3f23f8bc..64f46fda 100644 --- a/pyracf/common/segment_trait_error.py +++ b/pyracf/common/segment_trait_error.py @@ -9,8 +9,10 @@ class SegmentTraitError(Exception): def __init__(self, bad_traits: list, profile_type: str) -> None: self.message = "Unable to build Security Request.\n\n" for trait in bad_traits: - self.message += f"'{trait}' is not a known segment-trait " - self.message += f"combination for '{profile_type}'.\n" + self.message += ( + f"'{trait}' is not a known segment-trait " + + f"combination for '{profile_type}'.\n" + ) def __str__(self) -> str: return self.message diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.json similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.json rename to tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.json diff --git a/tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.xml similarity index 100% rename from tests/data_set/data_set_result_samples/extract_data_set_result_invalid_attribute_error.xml rename to tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.xml diff --git a/tests/data_set/test_data_set_constants.py b/tests/data_set/test_data_set_constants.py index d68a090a..fecebc30 100644 --- a/tests/data_set/test_data_set_constants.py +++ b/tests/data_set/test_data_set_constants.py @@ -58,11 +58,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_DICTIONARY = get_sample( "extract_data_set_result_base_only_error.json" ) -TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_XML = get_sample( - "extract_data_set_result_invalid_attribute_error.xml" +TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_XML = get_sample( + "extract_data_set_result_bad_attribute_error.xml" ) -TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY = get_sample( - "extract_data_set_result_invalid_attribute_error.json" +TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY = get_sample( + "extract_data_set_result_bad_attribute_error.json" ) # Delete Data Set diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 9f956397..4327dcc3 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -71,7 +71,7 @@ def test_data_set_admin_can_parse_add_data_set_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_XML, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_XML, TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -81,7 +81,7 @@ def test_data_set_admin_can_parse_add_data_set_error_xml( ) self.assertEqual( exception.exception.result, - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json b/tests/group/group_result_samples/extract_group_result_bad_attribute_error.json similarity index 100% rename from tests/group/group_result_samples/extract_group_result_invalid_attribute_error.json rename to tests/group/group_result_samples/extract_group_result_bad_attribute_error.json diff --git a/tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml b/tests/group/group_result_samples/extract_group_result_bad_attribute_error.xml similarity index 100% rename from tests/group/group_result_samples/extract_group_result_invalid_attribute_error.xml rename to tests/group/group_result_samples/extract_group_result_bad_attribute_error.xml diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index c22849b1..28186779 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -54,11 +54,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_ERROR_JSON = get_sample( "extract_group_result_base_only_error.json" ) -TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_XML = get_sample( - "extract_group_result_invalid_attribute_error.xml" +TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_XML = get_sample( + "extract_group_result_bad_attribute_error.xml" ) -TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY = get_sample( - "extract_group_result_invalid_attribute_error.json" +TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY = get_sample( + "extract_group_result_bad_attribute_error.json" ) # Delete Group diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 7ac63b95..6b7e255a 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -62,13 +62,13 @@ def test_group_admin_throws_error_on_add_existing_group( + f"'{group_name}' already exists as a '{self.group_admin._profile_type}' profile.", ) - # Error in command, TESTGRPP0 is invalid GROUP + # Error in command, TESTGRPP0 is bad GROUP def test_group_admin_can_parse_add_group_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_XML, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_XML, TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -77,7 +77,7 @@ def test_group_admin_can_parse_add_group_error_xml( ) self.assertEqual( exception.exception.result, - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_INVALID_ATTRIBUTE_ERROR_DICTIONARY, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ @@ -118,7 +118,7 @@ def test_group_admin_throws_error_on_alter_new_group( + f"'{group_name}' does not exist as a '{self.group_admin._profile_type}' profile.", ) - # Error: invalid gid "3000000000" + # Error: bad gid "3000000000" def test_group_admin_can_parse_alter_group_error_xml( self, call_racf_mock: Mock, diff --git a/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json b/tests/resource/resource_result_samples/extract_resource_result_bad_class_error.json similarity index 100% rename from tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.json rename to tests/resource/resource_result_samples/extract_resource_result_bad_class_error.json diff --git a/tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml b/tests/resource/resource_result_samples/extract_resource_result_bad_class_error.xml similarity index 100% rename from tests/resource/resource_result_samples/extract_resource_result_invalid_class_error.xml rename to tests/resource/resource_result_samples/extract_resource_result_bad_class_error.xml diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index f308e6f4..1d9edd89 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -52,11 +52,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_RESOURCE_RESULT_BASE_ERROR_DICTIONARY = get_sample( "extract_resource_result_base_error.json" ) -TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_XML = get_sample( - "extract_resource_result_invalid_class_error.xml" +TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_XML = get_sample( + "extract_resource_result_bad_class_error.xml" ) -TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_DICTIONARY = get_sample( - "extract_resource_result_invalid_class_error.json" +TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_DICTIONARY = get_sample( + "extract_resource_result_bad_class_error.json" ) # Delete Resource diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 632e44b6..7e9d9f04 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -63,20 +63,20 @@ def test_resource_admin_throws_error_on_add_existing_profile( + f"'{profile_name}' already exists as a profile in the '{class_name}' class.", ) - # Error: Invalid Entity Name ELIXTEST + # Error: bad Entity Name ELIXTEST def test_resource_admin_can_parse_add_resource_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_XML, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_XML, TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: self.resource_admin.add("TESTING", "ELIXTEST") self.assertEqual( exception.exception.result, - TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_INVALID_CLASS_ERROR_DICTIONARY, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_DICTIONARY, ) # ============================================================================ @@ -122,7 +122,7 @@ def test_resource_admin_throws_error_on_alter_new_profile( + f"'{profile_name}' does not exist as a profile in the '{class_name}' class.", ) - # Error: Invalid Universal Access ALL + # Error: bad Universal Access ALL def test_resource_admin_can_parse_alter_resource_error_xml( self, call_racf_mock: Mock, diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 3bfa719c..518b07b0 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -97,11 +97,11 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample( "extract_user_result_with_command_audit_trail.xml" ) -TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_XML = get_sample( - "extract_user_result_invalid_attribute_error.xml" +TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_XML = get_sample( + "extract_user_result_bad_attribute_error.xml" ) -TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_JSON = get_sample( - "extract_user_result_invalid_attribute_error.json" +TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_JSON = get_sample( + "extract_user_result_bad_attribute_error.json" ) TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML = get_sample( "extract_user_result_base_omvs_tso_revoke_resume.xml" diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index dc02d611..c9695ae3 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -66,13 +66,13 @@ def test_user_admin_throws_error_on_add_existing_user( + f"'{profile_name}' already exists as a '{self.user_admin._profile_type}' profile.", ) - # Error in command, SQUIDWARD is invalid USERID + # Error in command, SQUIDWARD is bad USERID def test_user_admin_can_parse_add_user_error_xml( self, call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestUserConstants.TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_XML, + TestUserConstants.TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_XML, TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -82,7 +82,7 @@ def test_user_admin_can_parse_add_user_error_xml( ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_EXTRACT_USER_RESULT_INVALID_ATTRIBUTE_JSON, + TestUserConstants.TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_JSON, ) # ============================================================================ @@ -123,7 +123,7 @@ def test_user_admin_throws_error_on_alter_new_user( + f"'{profile_name}' does not exist as a '{self.user_admin._profile_type}' profile.", ) - # Error: invalid uid '90000000000' + # Error: bad uid '90000000000' def test_user_admin_can_parse_alter_user_error_xml( self, call_racf_mock: Mock, @@ -231,7 +231,7 @@ def test_user_admin_password_redacted_alter_user_success_xml( self.assertNotIn(self.test_password, result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - # Error: invalid uid '90000000000' + # Error: bad uid '90000000000' def test_user_admin_password_redacted_alter_user_error_xml( self, call_racf_mock: Mock, @@ -277,7 +277,7 @@ def test_user_admin_passphrase_redacted_alter_user_success_xml( self.assertNotIn(self.test_passphrase, result_str) self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) - # Error: invalid uid '90000000000' + # Error: bad uid '90000000000' def test_user_admin_passphrase_redacted_alter_user_error_xml( self, call_racf_mock: Mock, @@ -325,7 +325,7 @@ def test_user_admin_passphrase_and_password_redacted_alter_user_success_xml( self.assertNotIn("(" + " " * (len(self.test_passphrase) + 2) + ")", result_str) self.assertNotIn("(" + " " * len(self.test_password) + ")", result_str) - # Error: invalid uid '90000000000' + # Error: bad uid '90000000000' def test_user_admin_passphrase_and_password_redacted_alter_user_error_xml( self, call_racf_mock: Mock, @@ -374,7 +374,7 @@ def test_user_admin_password_message_not_redacted_alter_user_success_xml( self.assertNotIn("(" + " " * len(self.simple_password) + ")", result_str) self.assertIn(self.simple_password, result_str) - # Error: invalid uid '90000000000' + # Error: bad uid '90000000000' def test_user_admin_password_message_not_redacted_alter_user_error_xml( self, call_racf_mock: Mock, diff --git a/tests/user/user_result_samples/extract_user_result_invalid_attribute_error.json b/tests/user/user_result_samples/extract_user_result_bad_attribute_error.json similarity index 100% rename from tests/user/user_result_samples/extract_user_result_invalid_attribute_error.json rename to tests/user/user_result_samples/extract_user_result_bad_attribute_error.json diff --git a/tests/user/user_result_samples/extract_user_result_invalid_attribute_error.xml b/tests/user/user_result_samples/extract_user_result_bad_attribute_error.xml similarity index 100% rename from tests/user/user_result_samples/extract_user_result_invalid_attribute_error.xml rename to tests/user/user_result_samples/extract_user_result_bad_attribute_error.xml From a2bb881a5923ed68e5f1798ca216da6fe2e213b3 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 13:00:13 -0400 Subject: [PATCH 48/72] Add operation flags back to unit testing Added Alter=True to Connection, Access, and Setropts Admin's Add/Alter command to establish operation flags. Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 2 +- pyracf/connection/connection_admin.py | 2 +- pyracf/setropts/setropts_admin.py | 2 +- tests/access/access_log_samples/permit_access_error.log | 4 ++-- tests/access/access_log_samples/permit_access_success.log | 4 ++-- tests/access/access_request_samples/permit_access_request.xml | 4 ++-- .../connection_log_samples/connect_connection_error.log | 2 +- .../connection_log_samples/connect_connection_success.log | 2 +- .../connection_request_samples/connect_connection_request.xml | 2 +- .../connection_give_group_access_attribute.xml | 2 +- .../connection_give_group_auditor_authority.xml | 2 +- .../connection_give_group_operations_authority.xml | 2 +- .../connection_give_group_special_authority.xml | 2 +- tests/setropts/setropts_log_samples/alter_setropts_error.log | 2 +- .../setropts/setropts_log_samples/alter_setropts_success.log | 2 +- .../setropts_request_samples/alter_setropts_request.xml | 2 +- .../setropts_request_samples/setropts_add_active_class.xml | 2 +- .../setropts_request_samples/setropts_add_active_classes.xml | 2 +- .../setropts_request_samples/setropts_add_audit_class.xml | 2 +- .../setropts_request_samples/setropts_add_audit_classes.xml | 2 +- .../setropts_add_generic_command_processing_class.xml | 2 +- .../setropts_add_generic_command_processing_classes.xml | 2 +- .../setropts_add_generic_profile_checking_class.xml | 2 +- .../setropts_add_generic_profile_checking_classes.xml | 2 +- .../setropts_add_generic_profile_sharing_class.xml | 2 +- .../setropts_add_generic_profile_sharing_classes.xml | 2 +- .../setropts_add_global_access_class.xml | 2 +- .../setropts_add_global_access_classes.xml | 2 +- .../setropts_request_samples/setropts_add_raclist_class.xml | 2 +- .../setropts_request_samples/setropts_add_raclist_classes.xml | 2 +- .../setropts_add_statistics_class.xml | 2 +- .../setropts_add_statistics_classes.xml | 2 +- .../setropts_request_samples/setropts_refresh_raclist.xml | 4 ++-- .../setropts_refresh_raclist_multiple.xml | 4 ++-- 34 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 4ac104d3..494ac4b1 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -67,7 +67,7 @@ def permit( traits["base:id"] = auth_id self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) - self._add_traits_directly_to_request_xml_with_no_segments(access_request) + self._add_traits_directly_to_request_xml_with_no_segments(access_request, alter=True) return self._make_request(access_request) def delete( diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index c5f33f31..f76af254 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -123,7 +123,7 @@ def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, byt """Establish or change a group connection.""" self._build_segment_dictionaries(traits) connection_request = ConnectionRequest(userid, group, "set") - self._add_traits_directly_to_request_xml_with_no_segments(connection_request) + self._add_traits_directly_to_request_xml_with_no_segments(connection_request, alter=True) return self._make_request(connection_request) def delete(self, userid: str, group: str) -> Union[dict, bytes]: diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 19597907..52734e8e 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -325,7 +325,7 @@ def alter(self, options: dict = {}) -> Union[dict, bytes]: """Update RACF options.""" self._build_segment_dictionaries(options) setropts_request = SetroptsRequest() - self._add_traits_directly_to_request_xml_with_no_segments(setropts_request) + self._add_traits_directly_to_request_xml_with_no_segments(setropts_request, alter=True) return self._make_request(setropts_request) # ============================================================================ diff --git a/tests/access/access_log_samples/permit_access_error.log b/tests/access/access_log_samples/permit_access_error.log index deaeaf6f..a4b8f7e7 100644 --- a/tests/access/access_log_samples/permit_access_error.log +++ b/tests/access/access_log_samples/permit_access_error.log @@ -25,8 +25,8 @@ - ALTER - MCGINLEY + ALTER + MCGINLEY diff --git a/tests/access/access_log_samples/permit_access_success.log b/tests/access/access_log_samples/permit_access_success.log index f7440155..8ab1b307 100644 --- a/tests/access/access_log_samples/permit_access_success.log +++ b/tests/access/access_log_samples/permit_access_success.log @@ -25,8 +25,8 @@ - NONE - ESWIFT + NONE + ESWIFT diff --git a/tests/access/access_request_samples/permit_access_request.xml b/tests/access/access_request_samples/permit_access_request.xml index 8771e90f..60ae67eb 100644 --- a/tests/access/access_request_samples/permit_access_request.xml +++ b/tests/access/access_request_samples/permit_access_request.xml @@ -1,6 +1,6 @@ - NONE - ESWIFT + NONE + ESWIFT \ No newline at end of file diff --git a/tests/connection/connection_log_samples/connect_connection_error.log b/tests/connection/connection_log_samples/connect_connection_error.log index 4fb7a2ba..c7473430 100644 --- a/tests/connection/connection_log_samples/connect_connection_error.log +++ b/tests/connection/connection_log_samples/connect_connection_error.log @@ -26,7 +26,7 @@ - + diff --git a/tests/connection/connection_log_samples/connect_connection_success.log b/tests/connection/connection_log_samples/connect_connection_success.log index a25b4c01..f7782fa8 100644 --- a/tests/connection/connection_log_samples/connect_connection_success.log +++ b/tests/connection/connection_log_samples/connect_connection_success.log @@ -26,7 +26,7 @@ - + diff --git a/tests/connection/connection_request_samples/connect_connection_request.xml b/tests/connection/connection_request_samples/connect_connection_request.xml index 7affef1e..f6c274d1 100644 --- a/tests/connection/connection_request_samples/connect_connection_request.xml +++ b/tests/connection/connection_request_samples/connect_connection_request.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_access_attribute.xml b/tests/connection/connection_request_samples/connection_give_group_access_attribute.xml index 92cf26c7..e5d15a33 100644 --- a/tests/connection/connection_request_samples/connection_give_group_access_attribute.xml +++ b/tests/connection/connection_request_samples/connection_give_group_access_attribute.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml b/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml index fa848e9b..8bb8b7af 100644 --- a/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_auditor_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml b/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml index c11cc010..cfaf13fa 100644 --- a/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_operations_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/connection/connection_request_samples/connection_give_group_special_authority.xml b/tests/connection/connection_request_samples/connection_give_group_special_authority.xml index cffa6721..b39b16c9 100644 --- a/tests/connection/connection_request_samples/connection_give_group_special_authority.xml +++ b/tests/connection/connection_request_samples/connection_give_group_special_authority.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/tests/setropts/setropts_log_samples/alter_setropts_error.log b/tests/setropts/setropts_log_samples/alter_setropts_error.log index 6058b6ef..246e426c 100644 --- a/tests/setropts/setropts_log_samples/alter_setropts_error.log +++ b/tests/setropts/setropts_log_samples/alter_setropts_error.log @@ -21,7 +21,7 @@ - ELIXTEST + ELIXTEST diff --git a/tests/setropts/setropts_log_samples/alter_setropts_success.log b/tests/setropts/setropts_log_samples/alter_setropts_success.log index 3f910df0..7bd71b7a 100644 --- a/tests/setropts/setropts_log_samples/alter_setropts_success.log +++ b/tests/setropts/setropts_log_samples/alter_setropts_success.log @@ -21,7 +21,7 @@ - ELIJTEST + ELIJTEST diff --git a/tests/setropts/setropts_request_samples/alter_setropts_request.xml b/tests/setropts/setropts_request_samples/alter_setropts_request.xml index 6a4ea90e..fd44ed7d 100644 --- a/tests/setropts/setropts_request_samples/alter_setropts_request.xml +++ b/tests/setropts/setropts_request_samples/alter_setropts_request.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_active_class.xml b/tests/setropts/setropts_request_samples/setropts_add_active_class.xml index b958f256..56930364 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_active_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_active_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml index 91b4edcc..50c0b32d 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_active_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_audit_class.xml b/tests/setropts/setropts_request_samples/setropts_add_audit_class.xml index 661f213e..2be3f6d0 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_audit_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_audit_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml index 7871f86b..d6d71cb3 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_audit_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_class.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_class.xml index cc8a60de..ad97a37a 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml index 4b6bea5c..1bf65492 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_command_processing_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_class.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_class.xml index 2b1120f9..6687060e 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml index fb4d71d5..9a077c4d 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_checking_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_class.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_class.xml index 4263b8b6..89407b8e 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml index 9334ea6d..ea221eeb 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_generic_profile_sharing_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_global_access_class.xml b/tests/setropts/setropts_request_samples/setropts_add_global_access_class.xml index d8c87459..ddc82b4a 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_global_access_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_global_access_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml index 979d0f52..cda59bd3 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_global_access_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_raclist_class.xml b/tests/setropts/setropts_request_samples/setropts_add_raclist_class.xml index 6a4ea90e..fd44ed7d 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_raclist_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_raclist_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml index effd0461..5bd8d4ac 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_raclist_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_statistics_class.xml b/tests/setropts/setropts_request_samples/setropts_add_statistics_class.xml index ea49762a..5a54beb9 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_statistics_class.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_statistics_class.xml @@ -1,5 +1,5 @@ - elijtest + elijtest \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml b/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml index 0b24d2f4..f76ed3d5 100644 --- a/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml +++ b/tests/setropts/setropts_request_samples/setropts_add_statistics_classes.xml @@ -1,5 +1,5 @@ - elijtest xfacilit + elijtest xfacilit \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_refresh_raclist.xml b/tests/setropts/setropts_request_samples/setropts_refresh_raclist.xml index 0908b47c..e7f90159 100644 --- a/tests/setropts/setropts_request_samples/setropts_refresh_raclist.xml +++ b/tests/setropts/setropts_request_samples/setropts_refresh_raclist.xml @@ -1,6 +1,6 @@ - elijtest - + elijtest + \ No newline at end of file diff --git a/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml b/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml index a4b09c0e..eec7ec01 100644 --- a/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml +++ b/tests/setropts/setropts_request_samples/setropts_refresh_raclist_multiple.xml @@ -1,6 +1,6 @@ - elijtest xfacilit - + elijtest xfacilit + \ No newline at end of file From 1fd006c9d50711b678812d17d34d903b641cb3fc Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 14:44:36 -0400 Subject: [PATCH 49/72] Minor Tweaks correction for bad find/replace Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 1 - pyracf/connection/connection_admin.py | 2 +- pyracf/data_set/data_set_admin.py | 1 - pyracf/resource/resource_admin.py | 2 +- tests/data_set/test_data_set_constants.py | 4 ++-- tests/data_set/test_data_set_result_parser.py | 4 ++-- tests/group/test_group_constants.py | 4 ++-- tests/group/test_group_result_parser.py | 4 ++-- tests/resource/test_resource_constants.py | 4 ++-- tests/resource/test_resource_result_parser.py | 4 ++-- tests/user/test_user_constants.py | 4 ++-- tests/user/test_user_result_parser.py | 4 ++-- 12 files changed, 18 insertions(+), 20 deletions(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 494ac4b1..da81be69 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -27,7 +27,6 @@ def __init__( "base:model_profile_generic": "racf:fgeneric", "base:model_profile_volume": "racf:fvolume", "base:id": "authid", - "base:profile": "racf:profile", # Not documented? "base:reset": "racf:reset", "base:volume": "racf:volume", "base:when_partner_lu_name": "racf:whenappc", diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index f76af254..6d5d2563 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -120,7 +120,7 @@ def take_away_group_access_attribute( # Base Functions # ============================================================================ def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: - """Establish or change a group connection.""" + """Create or change a group connection.""" self._build_segment_dictionaries(traits) connection_request = ConnectionRequest(userid, group, "set") self._add_traits_directly_to_request_xml_with_no_segments(connection_request, alter=True) diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index b5ab7eec..9c5c3520 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -46,7 +46,6 @@ def __init__( "base:data_set_model_profile": "racf:model", "base:notify_userid": "racf:notify", "base:owner": "racf:owner", - "base:profile": "racf:profile", # Not documented? "base:tape_data_set_security_retention_period": "racf:retpd", "base:security_label": "racf:seclabel", "base:security_level": "racf:seclevel", diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 619ca26e..13b9467e 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -84,7 +84,7 @@ def __init__( "cfdef:mixed_case_allowed": "mixed", "cfdef:min_numeric_value": "minvalue", "cfdef:max_field_length": "maxlength", - "cfdef:max_numeric_value": "other", # I think this is wrong... + "cfdef:max_numeric_value": "maxvalue", "cfdef:valid_other_characters": "other", "cfdef:validation_rexx_exec": "racf:cfvalrx", }, diff --git a/tests/data_set/test_data_set_constants.py b/tests/data_set/test_data_set_constants.py index fecebc30..cf050ab2 100644 --- a/tests/data_set/test_data_set_constants.py +++ b/tests/data_set/test_data_set_constants.py @@ -58,10 +58,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_ERROR_DICTIONARY = get_sample( "extract_data_set_result_base_only_error.json" ) -TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_XML = get_sample( +TEST_EXTRACT_DATA_SET_RESULT_BAD_ATTRIBUTE_ERROR_XML = get_sample( "extract_data_set_result_bad_attribute_error.xml" ) -TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY = get_sample( +TEST_EXTRACT_DATA_SET_RESULT_BAD_ATTRIBUTE_ERROR_DICTIONARY = get_sample( "extract_data_set_result_bad_attribute_error.json" ) diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 4327dcc3..bc1698aa 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -71,7 +71,7 @@ def test_data_set_admin_can_parse_add_data_set_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_XML, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BAD_ATTRIBUTE_ERROR_XML, TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -81,7 +81,7 @@ def test_data_set_admin_can_parse_add_data_set_error_xml( ) self.assertEqual( exception.exception.result, - TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY, + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BAD_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index 28186779..a971c3be 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -54,10 +54,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_ERROR_JSON = get_sample( "extract_group_result_base_only_error.json" ) -TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_XML = get_sample( +TEST_EXTRACT_GROUP_RESULT_BAD_ATTRIBUTE_ERROR_XML = get_sample( "extract_group_result_bad_attribute_error.xml" ) -TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY = get_sample( +TEST_EXTRACT_GROUP_RESULT_BAD_ATTRIBUTE_ERROR_DICTIONARY = get_sample( "extract_group_result_bad_attribute_error.json" ) diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 6b7e255a..1b5cda83 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -68,7 +68,7 @@ def test_group_admin_can_parse_add_group_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_XML, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BAD_ATTRIBUTE_ERROR_XML, TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -77,7 +77,7 @@ def test_group_admin_can_parse_add_group_error_xml( ) self.assertEqual( exception.exception.result, - TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_bad_ATTRIBUTE_ERROR_DICTIONARY, + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BAD_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index 1d9edd89..4efa9571 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -52,10 +52,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_RESOURCE_RESULT_BASE_ERROR_DICTIONARY = get_sample( "extract_resource_result_base_error.json" ) -TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_XML = get_sample( +TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_XML = get_sample( "extract_resource_result_bad_class_error.xml" ) -TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_DICTIONARY = get_sample( +TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_DICTIONARY = get_sample( "extract_resource_result_bad_class_error.json" ) diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 7e9d9f04..c3e08489 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -69,14 +69,14 @@ def test_resource_admin_can_parse_add_resource_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_XML, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_XML, TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: self.resource_admin.add("TESTING", "ELIXTEST") self.assertEqual( exception.exception.result, - TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_bad_CLASS_ERROR_DICTIONARY, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_DICTIONARY, ) # ============================================================================ diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 518b07b0..951b0eaf 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -97,10 +97,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample( "extract_user_result_with_command_audit_trail.xml" ) -TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_XML = get_sample( +TEST_EXTRACT_USER_RESULT_BAD_ATTRIBUTE_XML = get_sample( "extract_user_result_bad_attribute_error.xml" ) -TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_JSON = get_sample( +TEST_EXTRACT_USER_RESULT_BAD_ATTRIBUTE_JSON = get_sample( "extract_user_result_bad_attribute_error.json" ) TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML = get_sample( diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index c9695ae3..28f037a3 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -72,7 +72,7 @@ def test_user_admin_can_parse_add_user_error_xml( call_racf_mock: Mock, ): call_racf_mock.side_effect = [ - TestUserConstants.TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_XML, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BAD_ATTRIBUTE_XML, TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML, ] with self.assertRaises(SecurityRequestError) as exception: @@ -82,7 +82,7 @@ def test_user_admin_can_parse_add_user_error_xml( ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_EXTRACT_USER_RESULT_bad_ATTRIBUTE_JSON, + TestUserConstants.TEST_EXTRACT_USER_RESULT_BAD_ATTRIBUTE_JSON, ) # ============================================================================ From 4ef2eba1b71c5dd63821c08b5de31be1c3433800 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 15:01:43 -0400 Subject: [PATCH 50/72] Remove extraneous Access Trait Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index da81be69..1b40a864 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -26,7 +26,6 @@ def __init__( "base:model_profile": "racf:fprofile", "base:model_profile_generic": "racf:fgeneric", "base:model_profile_volume": "racf:fvolume", - "base:id": "authid", "base:reset": "racf:reset", "base:volume": "racf:volume", "base:when_partner_lu_name": "racf:whenappc", From 76e57e35470773be2e7ea139c99fe10afc970981 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 27 Oct 2023 15:22:34 -0400 Subject: [PATCH 51/72] Change ID to AUTH_ID Base:ID was NOT extraneous in Access Admin, changed to AUTH_ID Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 5 +++-- tests/access/access_log_samples/permit_access_error.log | 2 +- tests/access/access_log_samples/permit_access_success.log | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 1b40a864..79283685 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -26,6 +26,7 @@ def __init__( "base:model_profile": "racf:fprofile", "base:model_profile_generic": "racf:fgeneric", "base:model_profile_volume": "racf:fvolume", + "base:auth_id": "authid", "base:reset": "racf:reset", "base:volume": "racf:volume", "base:when_partner_lu_name": "racf:whenappc", @@ -62,7 +63,7 @@ def permit( generic: bool = False, ) -> Union[dict, bytes]: """Change a permission (or add a new one)""" - traits["base:id"] = auth_id + traits["base:auth_id"] = auth_id self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments(access_request, alter=True) @@ -77,7 +78,7 @@ def delete( generic: bool = False, ) -> Union[dict, bytes]: """Delete a permission.""" - traits = {"base:id": auth_id} + traits = {"base:auth_id": auth_id} self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "del", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments(access_request) diff --git a/tests/access/access_log_samples/permit_access_error.log b/tests/access/access_log_samples/permit_access_error.log index a4b8f7e7..28151cbf 100644 --- a/tests/access/access_log_samples/permit_access_error.log +++ b/tests/access/access_log_samples/permit_access_error.log @@ -10,7 +10,7 @@ "value": "ALTER", "operation": null }, - "base:id": { + "base:auth_id": { "value": "MCGINLEY", "operation": null } diff --git a/tests/access/access_log_samples/permit_access_success.log b/tests/access/access_log_samples/permit_access_success.log index 8ab1b307..d82660a9 100644 --- a/tests/access/access_log_samples/permit_access_success.log +++ b/tests/access/access_log_samples/permit_access_success.log @@ -10,7 +10,7 @@ "value": "NONE", "operation": null }, - "base:id": { + "base:auth_id": { "value": "ESWIFT", "operation": null } From 64fa73aad8195b1ad732f1c23a4ae1749aecf9f6 Mon Sep 17 00:00:00 2001 From: Elijah Swift <86801927+ElijahSwiftIBM@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:52:33 -0400 Subject: [PATCH 52/72] Update access_admin.py Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 79283685..c2c50660 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -62,7 +62,7 @@ def permit( volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: - """Change a permission (or add a new one)""" + """Create or change a permission""" traits["base:auth_id"] = auth_id self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) From 7af4a9510c0158c6181403acda03766fb4b19a8b Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Sun, 29 Oct 2023 15:18:28 -0400 Subject: [PATCH 53/72] Formatting and Docstring Changes Formatting and Docstring Changes Also added result parser test for custom secrets on userid alter. Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 4 +- pyracf/common/add_operation_error.py | 2 +- pyracf/common/alter_operation_error.py | 2 +- pyracf/connection/connection_admin.py | 4 +- pyracf/setropts/setropts_admin.py | 4 +- tests/data_set/test_data_set_result_parser.py | 4 +- tests/group/test_group_result_parser.py | 4 +- tests/resource/test_resource_result_parser.py | 4 +- tests/setropts/test_setropts_setters.py | 6 +-- tests/user/test_user_constants.py | 6 +++ tests/user/test_user_debug_logging.py | 6 +-- tests/user/test_user_result_parser.py | 52 ++++++++++++++++++- .../alter_user_result_error_uid_secret.json | 27 ++++++++++ .../alter_user_result_extended_success.json | 22 ++++++++ 14 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 tests/user/user_result_samples/alter_user_result_error_uid_secret.json create mode 100644 tests/user/user_result_samples/alter_user_result_extended_success.json diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index c2c50660..40a129d7 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -66,7 +66,9 @@ def permit( traits["base:auth_id"] = auth_id self._build_segment_dictionaries(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) - self._add_traits_directly_to_request_xml_with_no_segments(access_request, alter=True) + self._add_traits_directly_to_request_xml_with_no_segments( + access_request, alter=True + ) return self._make_request(access_request) def delete( diff --git a/pyracf/common/add_operation_error.py b/pyracf/common/add_operation_error.py index 4d1a1f4f..855c6247 100644 --- a/pyracf/common/add_operation_error.py +++ b/pyracf/common/add_operation_error.py @@ -7,7 +7,7 @@ class AddOperationError(Exception): """ def __init__(self, profile_name: str, class_name: str) -> None: - self.message = "Security request made to IRRSMO00 failed." + self.message = "Refusing to make security request to IRRSMO00." admin_types = ["user", "group", "dataSet"] if class_name not in admin_types: self.message += ( diff --git a/pyracf/common/alter_operation_error.py b/pyracf/common/alter_operation_error.py index 67495833..fbec601f 100644 --- a/pyracf/common/alter_operation_error.py +++ b/pyracf/common/alter_operation_error.py @@ -7,7 +7,7 @@ class AlterOperationError(Exception): """ def __init__(self, profile_name: str, class_name: str) -> None: - self.message = "Security request made to IRRSMO00 failed." + self.message = "Refusing to make security request to IRRSMO00." admin_types = ["user", "group", "dataSet"] if class_name not in admin_types: self.message += ( diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index 6d5d2563..43049de5 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -123,7 +123,9 @@ def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, byt """Create or change a group connection.""" self._build_segment_dictionaries(traits) connection_request = ConnectionRequest(userid, group, "set") - self._add_traits_directly_to_request_xml_with_no_segments(connection_request, alter=True) + self._add_traits_directly_to_request_xml_with_no_segments( + connection_request, alter=True + ) return self._make_request(connection_request) def delete(self, userid: str, group: str) -> Union[dict, bytes]: diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 52734e8e..12fcd952 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -325,7 +325,9 @@ def alter(self, options: dict = {}) -> Union[dict, bytes]: """Update RACF options.""" self._build_segment_dictionaries(options) setropts_request = SetroptsRequest() - self._add_traits_directly_to_request_xml_with_no_segments(setropts_request, alter=True) + self._add_traits_directly_to_request_xml_with_no_segments( + setropts_request, alter=True + ) return self._make_request(setropts_request) # ============================================================================ diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index bc1698aa..27c0070b 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -59,7 +59,7 @@ def test_data_set_admin_thows_error_on_add_existing_data_set_profile( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' already exists as a " + f"'{self.data_set_admin._profile_type}' profile.", @@ -119,7 +119,7 @@ def test_data_set_admin_thows_error_on_alter_new_data_set_profile( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' does not exist as a " + f"'{self.data_set_admin._profile_type}' profile.", diff --git a/tests/group/test_group_result_parser.py b/tests/group/test_group_result_parser.py index 1b5cda83..b02441da 100644 --- a/tests/group/test_group_result_parser.py +++ b/tests/group/test_group_result_parser.py @@ -57,7 +57,7 @@ def test_group_admin_throws_error_on_add_existing_group( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{group_name}' already exists as a '{self.group_admin._profile_type}' profile.", ) @@ -113,7 +113,7 @@ def test_group_admin_throws_error_on_alter_new_group( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{group_name}' does not exist as a '{self.group_admin._profile_type}' profile.", ) diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index c3e08489..8c830103 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -58,7 +58,7 @@ def test_resource_admin_throws_error_on_add_existing_profile( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' already exists as a profile in the '{class_name}' class.", ) @@ -117,7 +117,7 @@ def test_resource_admin_throws_error_on_alter_new_profile( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' does not exist as a profile in the '{class_name}' class.", ) diff --git a/tests/setropts/test_setropts_setters.py b/tests/setropts/test_setropts_setters.py index 4c7c44e3..773c9b08 100644 --- a/tests/setropts/test_setropts_setters.py +++ b/tests/setropts/test_setropts_setters.py @@ -19,7 +19,7 @@ class TestSetroptsSetters(unittest.TestCase): setropts_admin = SetroptsAdmin(generate_requests_only=True) # ============================================================================ - # Class adders + # Class Adders # ============================================================================ def test_setropts_admin_build_add_audit_class_request(self): result = self.setropts_admin.add_audit_classes("elijtest") @@ -199,7 +199,7 @@ def test_setropts_admin_build_add_raclist_classes_request_list(self): ) # ============================================================================ - # Class removers + # Class Removers # ============================================================================ def test_setropts_admin_build_remove_audit_class_request(self): result = self.setropts_admin.remove_audit_classes("elijtest") @@ -383,7 +383,7 @@ def test_setropts_admin_build_remove_raclist_classes_request_list(self): ) # ============================================================================ - # Raclist refresh + # Raclist Refresh # ============================================================================ def test_setropts_admin_build_refresh_raclist_request(self): result = self.setropts_admin.refresh_raclist("elijtest") diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 951b0eaf..e4d05852 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -65,6 +65,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_XML = get_sample( "alter_user_result_extended_success.xml" ) +TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_DICTIONARY = get_sample( + "alter_user_result_extended_success.json" +) +TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY = get_sample( + "alter_user_result_error_uid_secret.json" +) # Extract User TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML = get_sample( diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index 74268420..f055e128 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -319,11 +319,7 @@ def test_alter_user_request_debug_log_additional_secret_added_get_redacted_on_er TestUserConstants.TEST_ALTER_USER_ADDITIONAL_SECRET_ADDED_ERROR_LOG, ) self.assertNotIn( - "(" - + str( - TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR["omvs:uid"] - ) - + ")", + f"({TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR['omvs:uid']})", error_log, ) diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 28f037a3..051c0357 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -61,7 +61,7 @@ def test_user_admin_throws_error_on_add_existing_user( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' already exists as a '{self.user_admin._profile_type}' profile.", ) @@ -118,7 +118,7 @@ def test_user_admin_throws_error_on_alter_new_user( ) self.assertEqual( exception.exception.message, - "Security request made to IRRSMO00 failed." + "Refusing to make security request to IRRSMO00." + "\n\nTarget profile " + f"'{profile_name}' does not exist as a '{self.user_admin._profile_type}' profile.", ) @@ -448,3 +448,51 @@ def test_user_admin_can_parse_extract_user_base_omvs_csdata_success_xml( user_admin.extract("squidwrd", segments=["omvs", "csdata"]), TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_CSDATA_SUCCESS_DICTIONARY, ) + + # ============================================================================ + # Add Additional Secrets + # ============================================================================ + def test_user_admin_custom_secret_redacted_on_success( + self, + call_racf_mock: Mock, + ): + user_admin = UserAdmin(additional_secret_traits=["omvs:uid"]) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_XML, + ] + result = user_admin.alter( + "squidwrd", + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED, + ) + self.assertEqual( + result, + TestUserConstants.TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_DICTIONARY, + ) + self.assertNotIn( + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED["omvs:uid"], + result, + ) + + def test_user_admin_custom_secret_redacted_on_error( + self, + call_racf_mock: Mock, + ): + user_admin = UserAdmin(debug=True, additional_secret_traits=["omvs:uid"]) + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_XML, + ] + with self.assertRaises(SecurityRequestError) as exception: + user_admin.alter( + "squidwrd", + traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR, + ) + self.assertEqual( + exception.exception.result, + TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY, + ) + self.assertNotIn( + f"({TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR['omvs:uid']})", + exception.exception.result, + ) diff --git a/tests/user/user_result_samples/alter_user_result_error_uid_secret.json b/tests/user/user_result_samples/alter_user_result_error_uid_secret.json new file mode 100644 index 00000000..4aef456c --- /dev/null +++ b/tests/user/user_result_samples/alter_user_result_error_uid_secret.json @@ -0,0 +1,27 @@ +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 8, + "returnCode": 16, + "reasonCode": 8, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********))", + "messages": [ + "IKJ56702I INVALID UID, 90000000000", + "IKJ56701I MISSING OMVS UID+", + "IKJ56701I MISSING OMVS USER ID (UID), 1-10 NUMERIC DIGITS" + ] + } + ] + }, + "returnCode": 4, + "reasonCode": 0 + } +} diff --git a/tests/user/user_result_samples/alter_user_result_extended_success.json b/tests/user/user_result_samples/alter_user_result_extended_success.json new file mode 100644 index 00000000..926a9785 --- /dev/null +++ b/tests/user/user_result_samples/alter_user_result_extended_success.json @@ -0,0 +1,22 @@ +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "set", + "requestId": "UserRequest", + "info": [ + "Definition exists. Add command skipped due to precheck option" + ], + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "ALTUSER SQUIDWRD NOSPECIAL OMVS (HOME ('/u/clarinet') NOPROGRAM UID (********))" + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} \ No newline at end of file From eead54fb9be95619711cecace1fd9927ff633946 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Mon, 30 Oct 2023 13:25:34 -0400 Subject: [PATCH 54/72] Add Experimental Note for Add Additional Secrets Signed-off-by: Elijah Swift --- tests/user/test_user_debug_logging.py | 2 ++ tests/user/test_user_result_parser.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index f055e128..346eb239 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -295,6 +295,8 @@ def test_alter_user_request_debug_log_additional_secret_added_get_redacted_on_su success_log, ) + # Secret redacted from command image but not from resulting error message. + # Marked experimental until resolved def test_alter_user_request_debug_log_additional_secret_added_get_redacted_on_error( self, call_racf_mock: Mock, diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 051c0357..64cb6739 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -474,6 +474,8 @@ def test_user_admin_custom_secret_redacted_on_success( result, ) + # Secret redacted from command image but not from resulting error message. + # Marked experimental until resolved def test_user_admin_custom_secret_redacted_on_error( self, call_racf_mock: Mock, From 2214ab5a187b8c7da0cbfa417c90eb7611e33809 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Mon, 30 Oct 2023 17:46:04 -0400 Subject: [PATCH 55/72] Add sub-functions to ResourceAdmin Add Drafted sub-functions to Resource Admin for testing. Signed-off-by: Elijah Swift --- pyracf/resource/resource_admin.py | 191 ++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 13b9467e..2dd0c09c 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -216,6 +216,197 @@ def get_my_access(self, resource: str, class_name: str) -> Union[str, bytes, Non profile = self.extract(resource, class_name, profile_only=True) return self._get_field(profile, "base", "yourAccess") + # ============================================================================ + # Class Administration + # ============================================================================ + def add_resource_class( + self, class_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new general resource class.""" + return self.add(resource=class_name, class_name="CDT", traits=traits) + + def alter_resource_class( + self, class_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing general resource class.""" + return self.alter(resource=class_name, class_name="CDT", traits=traits) + + def extract_resource_class(self, class_name: str) -> Union[dict, bytes]: + """Extract the attributes of a general resource class.""" + profile = self.extract( + resource=class_name, class_name="CDT", segments=["CDTINFO"] + ) + return profile["cdtinfo"] + + def delete_resource_class(self, class_name: str) -> Union[dict, bytes]: + """Delete a general resource class.""" + return self.delete(resource=class_name, class_name="CDT") + + # ============================================================================ + # Started Task Administration + # ============================================================================ + def add_started_task( + self, started_task_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new started task profile.""" + return self.add(resource=started_task_name, class_name="STARTED", traits=traits) + + def alter_started_task( + self, started_task_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing started task profile.""" + return self.alter( + resource=started_task_name, class_name="STARTED", traits=traits + ) + + def extract_started_task(self, started_task_name: str) -> Union[dict, bytes]: + """Extract the attributes of a started task profile.""" + profile = self.extract( + resource=started_task_name, class_name="STARTED", segments=["STDATA"] + ) + return profile["stdata"] + + def delete_started_task(self, started_task_name: str) -> Union[dict, bytes]: + """Delete a started task profile.""" + return self.delete(resource=started_task_name, class_name="STARTED") + + # ============================================================================ + # Custom Field Administration + # ============================================================================ + def add_custom_field( + self, custom_field_name: str, custom_field_type: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new custom field.""" + full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" + return self.add(resource=full_profile_name, class_name="CFIELD", traits=traits) + + def alter_custom_field( + self, custom_field_name: str, custom_field_type: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing custom field.""" + full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" + return self.alter( + resource=full_profile_name, class_name="CFIELD", traits=traits + ) + + def extract_custom_field( + self, custom_field_name: str, custom_field_type: str + ) -> Union[dict, bytes]: + """Extract the attributes of a custom field.""" + full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" + profile = self.extract( + resource=full_profile_name, class_name="CFIELD", segments=["CFDEF"] + ) + return profile["cfdef"] + + def delete_custom_field( + self, custom_field_name: str, custom_field_type: str + ) -> Union[dict, bytes]: + """Delete a custom field.""" + full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" + return self.delete(resource=full_profile_name, class_name="CFIELD") + + # ============================================================================ + # Kerberos Realm Administration + # ============================================================================ + def add_kerberos_realm( + self, kerberos_realm_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new kerberos realm profile.""" + return self.add(resource=kerberos_realm_name, class_name="REALM", traits=traits) + + def alter_kerberos_realm( + self, kerberos_realm_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing kerberos realm profile.""" + return self.alter( + resource=kerberos_realm_name, class_name="REALM", traits=traits + ) + + def extract_kerberos_realm(self, kerberos_realm_name: str) -> Union[dict, bytes]: + """Extract the attributes of a kerberos realm profile.""" + profile = self.extract( + resource=kerberos_realm_name, class_name="REALM", segments=["KERB"] + ) + return profile["kerb"] + + def delete_kerberos_realm(self, kerberos_realm_name: str) -> Union[dict, bytes]: + """Delete a kerberos realm profile.""" + return self.delete(resource=kerberos_realm_name, class_name="REALM") + + # ============================================================================ + # Signed Program Administration + # ============================================================================ + def add_signed_program( + self, signed_program_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new signed program profile.""" + if traits["sigver:library"]: + traits["base:member"] = traits["sigver:library"] + del traits["sigver:library"] + return self.add( + resource=signed_program_name, class_name="PROGRAM", traits=traits + ) + + def alter_signed_program( + self, signed_program_name: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing signed program profile.""" + if traits["sigver:library"]: + traits["base:member"] = traits["sigver:library"] + del traits["sigver:library"] + return self.alter( + resource=signed_program_name, class_name="PROGRAM", traits=traits + ) + + def extract_signed_program(self, signed_program_name: str) -> Union[dict, bytes]: + """Extract the attributes of a signed program profile.""" + profile = self.extract( + resource=signed_program_name, class_name="PROGRAM", segments=["SIGVER"] + ) + profile["sigver"]["library"] = profile["base"].get("member") + return profile["sigver"] + + def delete_signed_program(self, signed_program_name: str) -> Union[dict, bytes]: + """Delete a signed program profile.""" + return self.delete(resource=signed_program_name, class_name="PROGRAM") + + # ============================================================================ + # APPC Session Administration + # ============================================================================ + def add_appc_session( + self, net_id: str, local_lu: str, partner_lu: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Create a new APPC session profile.""" + full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" + return self.add(resource=full_profile_name, class_name="APPCLU", traits=traits) + + def alter_appc_session( + self, net_id: str, local_lu: str, partner_lu: str, traits: dict = {} + ) -> Union[dict, bytes]: + """Alter an existing APPC session profile.""" + full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" + return self.alter( + resource=full_profile_name, class_name="APPCLU", traits=traits + ) + + def extract_appc_session( + self, net_id: str, local_lu: str, partner_lu: str + ) -> Union[dict, bytes]: + """Extract the attributes of a APPC session profile.""" + full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" + profile = self.extract( + resource=full_profile_name, class_name="APPCLU", segments=["SESSION"] + ) + return profile["session"] + + def delete_appc_session( + self, net_id: str, local_lu: str, partner_lu: str + ) -> Union[dict, bytes]: + """Delete a APPC session.""" + full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" + return self.delete(resource=full_profile_name, class_name="APPCLU") + # ============================================================================ # Base Functions # ============================================================================ From c743a9a1861e081ba6048c027e5ffaa1bac33b00 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 09:20:28 -0400 Subject: [PATCH 56/72] Bug Fixes And Testing -Fix bug in Resource and Dataset Add/Alter errors that would allow generic profiles to cause issues -Test CFDEF MXLENGTH in case of typo in doc -Drive GenerateRequestOnly to faster output in Alter functions. Signed-off-by: Elijah Swift --- pyracf/data_set/data_set_admin.py | 24 ++++++++++++------- pyracf/group/group_admin.py | 5 ++++ pyracf/resource/resource_admin.py | 38 +++++++++++++++++++------------ 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 9c5c3520..52f6e7bf 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -110,15 +110,16 @@ def add( self._build_xml_segments(data_set_request) return self._make_request(data_set_request) try: - self.extract(data_set, volume=volume, generic=generic) + profile = self.extract(data_set, volume=volume, generic=generic, profile_only=True) + if self._get_field(profile, "base", "name") == data_set.lower(): + raise AddOperationError(data_set, self._profile_type) except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH35003I"): raise exception - self._build_segment_dictionaries(traits) - data_set_request = DataSetRequest(data_set, "set", volume, generic) - self._build_xml_segments(data_set_request) - return self._make_request(data_set_request) - raise AddOperationError(data_set, self._profile_type) + self._build_segment_dictionaries(traits) + data_set_request = DataSetRequest(data_set, "set", volume, generic) + self._build_xml_segments(data_set_request) + return self._make_request(data_set_request) def alter( self, @@ -127,11 +128,18 @@ def alter( volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: + """Alter an existing data set profile.""" + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + data_set_request = DataSetRequest(data_set, "set", volume, generic) + self._build_xml_segments(data_set_request, alter=True) + return self._make_request(data_set_request, irrsmo00_precheck=True) try: - self.extract(data_set) + profile = self.extract(data_set, volume=volume, generic=generic, profile_only=True) except SecurityRequestError: raise AlterOperationError(data_set, self._profile_type) - """Alter an existing data set profile.""" + if not self._get_field(profile, "base", "name") == data_set.lower(): + raise AlterOperationError(data_set, self._profile_type) self._build_segment_dictionaries(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request, alter=True) diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index f144ce7f..daaf0ec6 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -140,6 +140,11 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + group_request = GroupRequest(group, "set") + self._build_xml_segments(group_request, alter=True) + return self._make_request(group_request, irrsmo00_precheck=True) try: self.extract(group) except SecurityRequestError: diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 2dd0c09c..14f62e2b 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -65,7 +65,7 @@ def __init__( "cdtinfo:key_qualifiers": "keyqual", "cdtinfo:manditory_access_control_processing": "macprocessing", "cdtinfo:max_length": "maxlenx", - "cdtinfo:max_length_racroute": "maxlength", + "cdtinfo:max_length_entityx": "maxlength", "cdtinfo:member_class_name": "member", "cdtinfo:operations": "operations", "cdtinfo:valid_other_characters": "other", @@ -83,7 +83,7 @@ def __init__( "cfdef:list_heading_text": "listhead", "cfdef:mixed_case_allowed": "mixed", "cfdef:min_numeric_value": "minvalue", - "cfdef:max_field_length": "maxlength", + "cfdef:max_field_length": "mxlength", "cfdef:max_numeric_value": "maxvalue", "cfdef:valid_other_characters": "other", "cfdef:validation_rexx_exec": "racf:cfvalrx", @@ -234,7 +234,7 @@ def alter_resource_class( def extract_resource_class(self, class_name: str) -> Union[dict, bytes]: """Extract the attributes of a general resource class.""" profile = self.extract( - resource=class_name, class_name="CDT", segments=["CDTINFO"] + resource=class_name, class_name="CDT", segments=["cdtinfo"], profile_only=True ) return profile["cdtinfo"] @@ -262,7 +262,7 @@ def alter_started_task( def extract_started_task(self, started_task_name: str) -> Union[dict, bytes]: """Extract the attributes of a started task profile.""" profile = self.extract( - resource=started_task_name, class_name="STARTED", segments=["STDATA"] + resource=started_task_name, class_name="STARTED", segments=["stdata"], profile_only=True ) return profile["stdata"] @@ -295,7 +295,7 @@ def extract_custom_field( """Extract the attributes of a custom field.""" full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" profile = self.extract( - resource=full_profile_name, class_name="CFIELD", segments=["CFDEF"] + resource=full_profile_name, class_name="CFIELD", segments=["cfdef"], profile_only=True ) return profile["cfdef"] @@ -326,7 +326,7 @@ def alter_kerberos_realm( def extract_kerberos_realm(self, kerberos_realm_name: str) -> Union[dict, bytes]: """Extract the attributes of a kerberos realm profile.""" profile = self.extract( - resource=kerberos_realm_name, class_name="REALM", segments=["KERB"] + resource=kerberos_realm_name, class_name="REALM", segments=["kerb"], profile_only=True ) return profile["kerb"] @@ -362,7 +362,7 @@ def alter_signed_program( def extract_signed_program(self, signed_program_name: str) -> Union[dict, bytes]: """Extract the attributes of a signed program profile.""" profile = self.extract( - resource=signed_program_name, class_name="PROGRAM", segments=["SIGVER"] + resource=signed_program_name, class_name="PROGRAM", segments=["sigver"], profile_only=True ) profile["sigver"]["library"] = profile["base"].get("member") return profile["sigver"] @@ -396,7 +396,7 @@ def extract_appc_session( """Extract the attributes of a APPC session profile.""" full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" profile = self.extract( - resource=full_profile_name, class_name="APPCLU", segments=["SESSION"] + resource=full_profile_name, class_name="APPCLU", segments=["session"], profile_only=True ) return profile["session"] @@ -420,22 +420,30 @@ def add( self._build_xml_segments(profile_request) return self._make_request(profile_request) try: - self.extract(resource, class_name) + profile = self.extract(resource, class_name, profile_only=True) + if self._get_field(profile, "base", "name") == resource.lower(): + raise AddOperationError(resource, class_name) except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH13003I"): raise exception - self._build_segment_dictionaries(traits) - profile_request = ResourceRequest(resource, class_name, "set") - self._build_xml_segments(profile_request) - return self._make_request(profile_request) - raise AddOperationError(resource, class_name) + self._build_segment_dictionaries(traits) + profile_request = ResourceRequest(resource, class_name, "set") + self._build_xml_segments(profile_request) + return self._make_request(profile_request) def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, bytes]: """Alter an existing general resource profile.""" + if self._generate_requests_only: + self._build_segment_dictionaries(traits) + profile_request = ResourceRequest(resource, class_name, "set") + self._build_xml_segments(profile_request, alter=True) + return self._make_request(profile_request, irrsmo00_precheck=True) try: - self.extract(resource, class_name) + profile = self.extract(resource, class_name, profile_only=True) except SecurityRequestError: raise AlterOperationError(resource, class_name) + if not self._get_field(profile, "base", "name") == resource.lower(): + raise AlterOperationError(resource, class_name) self._build_segment_dictionaries(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) From dc1cfdf58ec2cc6ba67653f28738c317ed5106b6 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 12:17:55 -0400 Subject: [PATCH 57/72] Bug Fix and Formatting Translate null characters to blanks when not preceded by ">" to prevent premature string termination. Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 11 +++++++++++ pyracf/data_set/data_set_admin.py | 8 ++++++-- pyracf/resource/resource_admin.py | 30 ++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index 3845e412..b06dcfa5 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -55,6 +55,17 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) rsp ); + int i; + for (i = 1; i < rsp_len; i++){ + if (rsp[i] == 0) { + if (rsp[i-1] == '>') { + break; + } + else { + rsp[i] = ' '; + } + } + } return Py_BuildValue("y", rsp); } diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 52f6e7bf..41edc281 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -110,7 +110,9 @@ def add( self._build_xml_segments(data_set_request) return self._make_request(data_set_request) try: - profile = self.extract(data_set, volume=volume, generic=generic, profile_only=True) + profile = self.extract( + data_set, volume=volume, generic=generic, profile_only=True + ) if self._get_field(profile, "base", "name") == data_set.lower(): raise AddOperationError(data_set, self._profile_type) except SecurityRequestError as exception: @@ -135,7 +137,9 @@ def alter( self._build_xml_segments(data_set_request, alter=True) return self._make_request(data_set_request, irrsmo00_precheck=True) try: - profile = self.extract(data_set, volume=volume, generic=generic, profile_only=True) + profile = self.extract( + data_set, volume=volume, generic=generic, profile_only=True + ) except SecurityRequestError: raise AlterOperationError(data_set, self._profile_type) if not self._get_field(profile, "base", "name") == data_set.lower(): diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 14f62e2b..bdf0a161 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -234,7 +234,10 @@ def alter_resource_class( def extract_resource_class(self, class_name: str) -> Union[dict, bytes]: """Extract the attributes of a general resource class.""" profile = self.extract( - resource=class_name, class_name="CDT", segments=["cdtinfo"], profile_only=True + resource=class_name, + class_name="CDT", + segments=["cdtinfo"], + profile_only=True, ) return profile["cdtinfo"] @@ -262,7 +265,10 @@ def alter_started_task( def extract_started_task(self, started_task_name: str) -> Union[dict, bytes]: """Extract the attributes of a started task profile.""" profile = self.extract( - resource=started_task_name, class_name="STARTED", segments=["stdata"], profile_only=True + resource=started_task_name, + class_name="STARTED", + segments=["stdata"], + profile_only=True, ) return profile["stdata"] @@ -295,7 +301,10 @@ def extract_custom_field( """Extract the attributes of a custom field.""" full_profile_name = f"{custom_field_type}.csdata.{custom_field_name}" profile = self.extract( - resource=full_profile_name, class_name="CFIELD", segments=["cfdef"], profile_only=True + resource=full_profile_name, + class_name="CFIELD", + segments=["cfdef"], + profile_only=True, ) return profile["cfdef"] @@ -326,7 +335,10 @@ def alter_kerberos_realm( def extract_kerberos_realm(self, kerberos_realm_name: str) -> Union[dict, bytes]: """Extract the attributes of a kerberos realm profile.""" profile = self.extract( - resource=kerberos_realm_name, class_name="REALM", segments=["kerb"], profile_only=True + resource=kerberos_realm_name, + class_name="REALM", + segments=["kerb"], + profile_only=True, ) return profile["kerb"] @@ -362,7 +374,10 @@ def alter_signed_program( def extract_signed_program(self, signed_program_name: str) -> Union[dict, bytes]: """Extract the attributes of a signed program profile.""" profile = self.extract( - resource=signed_program_name, class_name="PROGRAM", segments=["sigver"], profile_only=True + resource=signed_program_name, + class_name="PROGRAM", + segments=["sigver"], + profile_only=True, ) profile["sigver"]["library"] = profile["base"].get("member") return profile["sigver"] @@ -396,7 +411,10 @@ def extract_appc_session( """Extract the attributes of a APPC session profile.""" full_profile_name = f"{net_id}.{local_lu}.{partner_lu}" profile = self.extract( - resource=full_profile_name, class_name="APPCLU", segments=["session"], profile_only=True + resource=full_profile_name, + class_name="APPCLU", + segments=["session"], + profile_only=True, ) return profile["session"] From 0227bf82eb2cfe983cc7fa20c10a88abbcf6a43d Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 13:35:45 -0400 Subject: [PATCH 58/72] Correct Workaround Algorithm Made it codepage agnostic: Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index b06dcfa5..80dac171 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -30,7 +30,7 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) VarStr_T userid = { 0, {0}}; unsigned int alet = 0; unsigned int acee = 0; - char rsp[BUFFER_SIZE+1]; + unsigned char rsp[BUFFER_SIZE+1]; memset(rsp, 0, BUFFER_SIZE); unsigned int saf_rc=0, racf_rc=0, racf_rsn=0; unsigned int num_parms=17, fn=1, opts = input_opts, rsp_len = sizeof(rsp)-1; @@ -55,14 +55,13 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) rsp ); - int i; - for (i = 1; i < rsp_len; i++){ + for (int i = 1; i < rsp_len; i++){ if (rsp[i] == 0) { - if (rsp[i-1] == '>') { + if (rsp[i-1] == 0x6E) { break; } else { - rsp[i] = ' '; + rsp[i] = 0x40; } } } From 8890a5d307c312b86ed2abb71b62f2d43e47bcd5 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 15:50:33 -0400 Subject: [PATCH 59/72] Mapping Extract Functions Mapping Extract fucntions Cleaning up c code Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 24 ++++++++------ pyracf/resource/resource_admin.py | 54 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index 80dac171..1ed849a2 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -13,6 +13,19 @@ typedef struct { char str[8]; } VarStr_T; +static char* null_byte_fix(char* string) { + for (int i = 1; i < rsp_len; i++){ + if (rsp[i] == 0) { + if (rsp[i-1] == 0x6E) { + break; + } + else { + rsp[i] = 0x40; + } + } + } +} + static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) { const unsigned int xml_len; const unsigned int input_opts; @@ -55,16 +68,7 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) rsp ); - for (int i = 1; i < rsp_len; i++){ - if (rsp[i] == 0) { - if (rsp[i-1] == 0x6E) { - break; - } - else { - rsp[i] = 0x40; - } - } - } + rsp = null_byte_fix(rsp); return Py_BuildValue("y", rsp); } diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index bdf0a161..7f556a1b 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -180,6 +180,60 @@ def __init__( "tme:roles": "racf:roles", }, } + self._extracted_key_value_pair_segment_traits_map = { + "cdtinfo": { + "case": "caseAllowed", + "defaultrc": "defaultRacrouteReturnCode", + "first": "validFirstCharacters", + "generic": "generic", + "genlist": "genlist", + "grouping": "groupingClassName", + "keyqual": "keyQualifiers", + "macprocessing": "manditoryAccessControlProcessing", + "maxlenx": "maxLength", + "maxlength": "maxLengthEntityx", + "member": "memberClassName", + "operations": "operations", + "other": "validOtherCharacters", + "posit": "positNumber", + "profilesallowed": "profilesAllowed", + "raclist": "raclistAllowed", + "signal": "sendEnfSignalOnProfileCreation", + "seclabelrequired": "securityLabelRequired", + "defaultuacc": "defaultUniversalAccess", + }, + "cfdef": { + "type": "customFieldDataType", + "first": "validFirstCharacters", + "help": "helpText", + "listhead": "listHeadingText", + "mixed": "mixedCaseAllowed", + "minvalue": "minNumericValue", + "mxlength": "maxFieldLength", + "maxvalue": "maxNumericValue", + "other": "validOtherCharacters", + "cfvalrx": "validationRexxExec", + }, + "kerb": { + "checkaddrs": "validateAddresses", + "deftktlife": "defaultTicketLife", + "encrypt": "encryptionAlgorithms", + "kerbname": "realmName", + "maxtktlf": "maxTicketLife", + "mintklife": "minTicketLife", + }, + "session": { + "convsec": "securityCheckingLevel", + "interval": "sessionKeyInterval", + "lock": "locked", + "sesskey": "sessionKey", + }, + "sigver": { + "failload": "failProgramLoadCondition", + "sigaudit": "logSignatureVerificationEvents", + "sigrequired": "signatureRequired", + }, + } super().__init__( "resource", debug=debug, From 3b9d1d5fe5b6771efca7e33d61925eb152b7700c Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 16:18:10 -0400 Subject: [PATCH 60/72] Fix issues with c code Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index 1ed849a2..c8037e80 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -13,14 +13,14 @@ typedef struct { char str[8]; } VarStr_T; -static char* null_byte_fix(char* string) { - for (int i = 1; i < rsp_len; i++){ - if (rsp[i] == 0) { - if (rsp[i-1] == 0x6E) { +void null_byte_fix(char* str, unsigned int str_len) { + for (int i = 1; i < str_len; i++){ + if (str[i] == 0) { + if (str[i-1] == 0x6E) { break; } else { - rsp[i] = 0x40; + str[i] = 0x40; } } } @@ -68,7 +68,7 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) rsp ); - rsp = null_byte_fix(rsp); + null_byte_fix(rsp,rsp_len); return Py_BuildValue("y", rsp); } From 3b34ca37fee1cafdc7c7edeba7e99737565a15b6 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Wed, 1 Nov 2023 23:17:43 -0400 Subject: [PATCH 61/72] Add Unit Testing for Sub Functions Add Unit Testing for Sub Functions Further optimize c code --- pyracf/common/irrsmo00.c | 2 +- pyracf/resource/resource_admin.py | 10 +- .../add_appc_session_request.xml | 3 + .../add_custom_field_request.xml | 3 + .../add_kerberos_realm_request.xml | 3 + .../add_resource_class_request.xml | 17 ++ .../add_signed_program_request.xml | 3 + .../add_started_task_request.xml | 3 + .../alter_appc_session_request.xml | 7 + .../alter_custom_field_request.xml | 9 + .../alter_kerberos_realm_request.xml | 7 + .../alter_resource_class_request.xml | 11 ++ .../alter_signed_program_request.xml | 7 + .../alter_started_task_request.xml | 7 + .../delete_appc_session_request.xml | 3 + .../delete_custom_field_request.xml | 3 + .../delete_kerberos_realm_request.xml | 3 + .../delete_resource_class_request.xml | 3 + .../delete_signed_program_request.xml | 3 + .../delete_started_task_request.xml | 3 + ...act_resource_result_base_cdtinfo_error.xml | 14 ++ ...t_resource_result_base_cdtinfo_success.xml | 58 ++++++ ...tract_resource_result_base_cfdef_error.xml | 14 ++ ...act_resource_result_base_cfdef_success.xml | 47 +++++ ...t_resource_result_base_generic_success.xml | 36 ++++ ...xtract_resource_result_base_kerb_error.xml | 14 ++ ...ract_resource_result_base_kerb_success.xml | 41 ++++ ...act_resource_result_base_session_error.xml | 14 ++ ...t_resource_result_base_session_success.xml | 41 ++++ ...ract_resource_result_base_sigver_error.xml | 14 ++ ...ct_resource_result_base_sigver_success.xml | 50 +++++ ...ract_resource_result_base_stdata_error.xml | 14 ++ ...ct_resource_result_base_stdata_success.xml | 44 +++++ tests/resource/test_resource_constants.py | 187 ++++++++++++++++++ tests/resource/test_resource_result_parser.py | 36 ++++ .../test_resource_sub_function_extracts.py | 170 ++++++++++++++++ .../test_resource_sub_function_requests.py | 163 +++++++++++++++ tests/test_runner.py | 8 + 38 files changed, 1069 insertions(+), 6 deletions(-) create mode 100644 tests/resource/resource_request_samples/add_appc_session_request.xml create mode 100644 tests/resource/resource_request_samples/add_custom_field_request.xml create mode 100644 tests/resource/resource_request_samples/add_kerberos_realm_request.xml create mode 100644 tests/resource/resource_request_samples/add_resource_class_request.xml create mode 100644 tests/resource/resource_request_samples/add_signed_program_request.xml create mode 100644 tests/resource/resource_request_samples/add_started_task_request.xml create mode 100644 tests/resource/resource_request_samples/alter_appc_session_request.xml create mode 100644 tests/resource/resource_request_samples/alter_custom_field_request.xml create mode 100644 tests/resource/resource_request_samples/alter_kerberos_realm_request.xml create mode 100644 tests/resource/resource_request_samples/alter_resource_class_request.xml create mode 100644 tests/resource/resource_request_samples/alter_signed_program_request.xml create mode 100644 tests/resource/resource_request_samples/alter_started_task_request.xml create mode 100644 tests/resource/resource_request_samples/delete_appc_session_request.xml create mode 100644 tests/resource/resource_request_samples/delete_custom_field_request.xml create mode 100644 tests/resource/resource_request_samples/delete_kerberos_realm_request.xml create mode 100644 tests/resource/resource_request_samples/delete_resource_class_request.xml create mode 100644 tests/resource/resource_request_samples/delete_signed_program_request.xml create mode 100644 tests/resource/resource_request_samples/delete_started_task_request.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_cfdef_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_cfdef_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_generic_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_kerb_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_kerb_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_session_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_session_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_sigver_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_sigver_success.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_stdata_error.xml create mode 100644 tests/resource/resource_result_samples/extract_resource_result_base_stdata_success.xml create mode 100644 tests/resource/test_resource_sub_function_extracts.py create mode 100644 tests/resource/test_resource_sub_function_requests.py diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index c8037e80..e4c901b3 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -17,7 +17,7 @@ void null_byte_fix(char* str, unsigned int str_len) { for (int i = 1; i < str_len; i++){ if (str[i] == 0) { if (str[i-1] == 0x6E) { - break; + return; } else { str[i] = 0x40; diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 7f556a1b..b62fb5be 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -187,8 +187,8 @@ def __init__( "first": "validFirstCharacters", "generic": "generic", "genlist": "genlist", - "grouping": "groupingClassName", - "keyqual": "keyQualifiers", + "group": "groupingClassName", + "keyqualifiers": "keyQualifiers", "macprocessing": "manditoryAccessControlProcessing", "maxlenx": "maxLength", "maxlength": "maxLengthEntityx", @@ -199,7 +199,7 @@ def __init__( "profilesallowed": "profilesAllowed", "raclist": "raclistAllowed", "signal": "sendEnfSignalOnProfileCreation", - "seclabelrequired": "securityLabelRequired", + "seclabelsrequired": "securityLabelsRequired", "defaultuacc": "defaultUniversalAccess", }, "cfdef": { @@ -407,7 +407,7 @@ def add_signed_program( self, signed_program_name: str, traits: dict = {} ) -> Union[dict, bytes]: """Create a new signed program profile.""" - if traits["sigver:library"]: + if "sigver:library" in traits: traits["base:member"] = traits["sigver:library"] del traits["sigver:library"] return self.add( @@ -418,7 +418,7 @@ def alter_signed_program( self, signed_program_name: str, traits: dict = {} ) -> Union[dict, bytes]: """Alter an existing signed program profile.""" - if traits["sigver:library"]: + if "sigver:library" in traits: traits["base:member"] = traits["sigver:library"] del traits["sigver:library"] return self.alter( diff --git a/tests/resource/resource_request_samples/add_appc_session_request.xml b/tests/resource/resource_request_samples/add_appc_session_request.xml new file mode 100644 index 00000000..7e8c87cf --- /dev/null +++ b/tests/resource/resource_request_samples/add_appc_session_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/add_custom_field_request.xml b/tests/resource/resource_request_samples/add_custom_field_request.xml new file mode 100644 index 00000000..454fdabd --- /dev/null +++ b/tests/resource/resource_request_samples/add_custom_field_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/add_kerberos_realm_request.xml b/tests/resource/resource_request_samples/add_kerberos_realm_request.xml new file mode 100644 index 00000000..5ae3d3aa --- /dev/null +++ b/tests/resource/resource_request_samples/add_kerberos_realm_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/add_resource_class_request.xml b/tests/resource/resource_request_samples/add_resource_class_request.xml new file mode 100644 index 00000000..0e02bab1 --- /dev/null +++ b/tests/resource/resource_request_samples/add_resource_class_request.xml @@ -0,0 +1,17 @@ + + + + UPPER + ALPHA + ALPHA NUMERIC + 246 + 246 + 0 + YES + 200 + 8 + NONE + ALLOWED + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/add_signed_program_request.xml b/tests/resource/resource_request_samples/add_signed_program_request.xml new file mode 100644 index 00000000..05a507b9 --- /dev/null +++ b/tests/resource/resource_request_samples/add_signed_program_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/add_started_task_request.xml b/tests/resource/resource_request_samples/add_started_task_request.xml new file mode 100644 index 00000000..c069b086 --- /dev/null +++ b/tests/resource/resource_request_samples/add_started_task_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_appc_session_request.xml b/tests/resource/resource_request_samples/alter_appc_session_request.xml new file mode 100644 index 00000000..b972bcee --- /dev/null +++ b/tests/resource/resource_request_samples/alter_appc_session_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_custom_field_request.xml b/tests/resource/resource_request_samples/alter_custom_field_request.xml new file mode 100644 index 00000000..974d407b --- /dev/null +++ b/tests/resource/resource_request_samples/alter_custom_field_request.xml @@ -0,0 +1,9 @@ + + + + Favorite TV Show + ALPHA + ALPHA + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_kerberos_realm_request.xml b/tests/resource/resource_request_samples/alter_kerberos_realm_request.xml new file mode 100644 index 00000000..199ae979 --- /dev/null +++ b/tests/resource/resource_request_samples/alter_kerberos_realm_request.xml @@ -0,0 +1,7 @@ + + + + AES128 + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_resource_class_request.xml b/tests/resource/resource_request_samples/alter_resource_class_request.xml new file mode 100644 index 00000000..532cbe0b --- /dev/null +++ b/tests/resource/resource_request_samples/alter_resource_class_request.xml @@ -0,0 +1,11 @@ + + + + ALPHA NUMERIC + ALPHA + NO + 4 + READ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_signed_program_request.xml b/tests/resource/resource_request_samples/alter_signed_program_request.xml new file mode 100644 index 00000000..35a63047 --- /dev/null +++ b/tests/resource/resource_request_samples/alter_signed_program_request.xml @@ -0,0 +1,7 @@ + + + + SUCCESS + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/alter_started_task_request.xml b/tests/resource/resource_request_samples/alter_started_task_request.xml new file mode 100644 index 00000000..97c9289e --- /dev/null +++ b/tests/resource/resource_request_samples/alter_started_task_request.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_appc_session_request.xml b/tests/resource/resource_request_samples/delete_appc_session_request.xml new file mode 100644 index 00000000..896d662e --- /dev/null +++ b/tests/resource/resource_request_samples/delete_appc_session_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_custom_field_request.xml b/tests/resource/resource_request_samples/delete_custom_field_request.xml new file mode 100644 index 00000000..ab75dbfb --- /dev/null +++ b/tests/resource/resource_request_samples/delete_custom_field_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_kerberos_realm_request.xml b/tests/resource/resource_request_samples/delete_kerberos_realm_request.xml new file mode 100644 index 00000000..b0e6a124 --- /dev/null +++ b/tests/resource/resource_request_samples/delete_kerberos_realm_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_resource_class_request.xml b/tests/resource/resource_request_samples/delete_resource_class_request.xml new file mode 100644 index 00000000..c5fe1627 --- /dev/null +++ b/tests/resource/resource_request_samples/delete_resource_class_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_signed_program_request.xml b/tests/resource/resource_request_samples/delete_signed_program_request.xml new file mode 100644 index 00000000..838b1074 --- /dev/null +++ b/tests/resource/resource_request_samples/delete_signed_program_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_request_samples/delete_started_task_request.xml b/tests/resource/resource_request_samples/delete_started_task_request.xml new file mode 100644 index 00000000..7956543b --- /dev/null +++ b/tests/resource/resource_request_samples/delete_started_task_request.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_error.xml new file mode 100644 index 00000000..b7162734 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST CDT (SHELCITY) CDTINFO + ICH13003I TESTING NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_success.xml new file mode 100644 index 00000000..bebced95 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_cdtinfo_success.xml @@ -0,0 +1,58 @@ + + + + + 0 + 0 + 0 + RLIST CDT (SHELCITY) CDTINFO + CLASS NAME + ----- ---- + CDT SHELCITY + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE ALTER NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + CDTINFO INFORMATION + ------------------- + CASE = UPPER + DEFAULTRC = 008 + DEFAULTUACC = NONE + FIRST = ALPHA + GENLIST = DISALLOWED + GENERIC = ALLOWED + GROUP = + KEYQUALIFIERS = 0000000000 + MACPROCESSING = NORMAL + MAXLENGTH = 246 + MAXLENX = 0000000246 + MEMBER = + OPERATIONS = NO + OTHER = ALPHA NUMERIC + POSIT = 0000000200 + PROFILESALLOWED = YES + RACLIST = ALLOWED + SECLABELSREQUIRED = NO + SIGNAL = NO + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_error.xml new file mode 100644 index 00000000..23e544ba --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST CFIELD (USER.CSDATA.TVSHOW) CFDEF + ICH13003I USER.CSDATA.TVSHOW NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_success.xml new file mode 100644 index 00000000..6808f253 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_cfdef_success.xml @@ -0,0 +1,47 @@ + + + + + 0 + 0 + 0 + RLIST CFIELD (USER.CSDATA.TVSHOW) CFDEF + CLASS NAME + ----- ---- + CFIELD USER.CSDATA.TVSHOW + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE ALTER NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + CFDEF INFORMATION + ----------------- + TYPE = CHAR + MAXLENGTH = NONE + MAXVALUE = NONE + MINVALUE = NONE + FIRST = ALPHA + OTHER = ALPHA + MIXED = NO + HELP = FAVORITE TV SHOW + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_generic_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_generic_success.xml new file mode 100644 index 00000000..26342807 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_generic_success.xml @@ -0,0 +1,36 @@ + + + + + 0 + 0 + 0 + RLIST ELIJTEST (TESTING) + CLASS NAME + ----- ---- + ELIJTEST TEST* + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT READ READ NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_kerb_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_kerb_error.xml new file mode 100644 index 00000000..aa45018f --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_kerb_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST REALM (TSTREALM) KERB + ICH13003I TSTREALM NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_kerb_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_kerb_success.xml new file mode 100644 index 00000000..3f83084d --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_kerb_success.xml @@ -0,0 +1,41 @@ + + + + + 0 + 0 + 0 + RLIST REALM (TSTREALM) KERB + CLASS NAME + ----- ---- + REALM TSTREALM + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE ALTER NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + KERB INFORMATION + ---------------- + KEY ENCRYPTION TYPE= DES DES3 DESD AES128 AES256 AES128SHA2 AES256SHA2 + CHECK ADDRESSES= NO + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_session_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_session_error.xml new file mode 100644 index 00000000..47dace61 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_session_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST APPCLU (TSTNET.TSTLOCLU.TSTPRTLU) SESSION + ICH13003I TSTNET.TSTLOCLU.TSTPRTLU NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_session_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_session_success.xml new file mode 100644 index 00000000..028679ec --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_session_success.xml @@ -0,0 +1,41 @@ + + + + + 0 + 0 + 0 + RLIST APPCLU (TSTNET.TSTLOCLU.TSTPRTLU) SESSION + CLASS NAME + ----- ---- + APPCLU TSTNET.TSTLOCLU.TSTPRTLU + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE ALTER NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + SESSION INFORMATION + ------------------- + SESSION KEY INTERVAL IS UNLIMITED + LOCKED + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_sigver_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_sigver_error.xml new file mode 100644 index 00000000..fd0d4b71 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_sigver_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST PROGRAM (TESTPRGM) SIGVER + ICH13003I TESTPRGM NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_sigver_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_sigver_success.xml new file mode 100644 index 00000000..44f27b64 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_sigver_success.xml @@ -0,0 +1,50 @@ + + + + + 0 + 0 + 0 + RLIST PROGRAM (TESTPRGM) SIGVER + CLASS NAME + ----- ---- + PROGRAM TESTPRGM + + MEMBER CLASS NAME + ------ ----- ---- + PMBR + + DATA SET NAME VOLSER PADS CHECKING + -------------------------------------------- ------ ------------- + NONE + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE ALTER NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + SIGVER INFORMATION + ------------------ + SIGREQUIRED = NO + FAILLOAD = NEVER + SIGAUDIT = SUCCESS + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_stdata_error.xml b/tests/resource/resource_result_samples/extract_resource_result_base_stdata_error.xml new file mode 100644 index 00000000..3c30b137 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_stdata_error.xml @@ -0,0 +1,14 @@ + + + + + 8 + 16 + 4 + RLIST STARTED (TSTTSKEL) STDATA + ICH13003I TSTTSKEL NOT FOUND + + + 4 + 0 + \ No newline at end of file diff --git a/tests/resource/resource_result_samples/extract_resource_result_base_stdata_success.xml b/tests/resource/resource_result_samples/extract_resource_result_base_stdata_success.xml new file mode 100644 index 00000000..cf4d8f1c --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_base_stdata_success.xml @@ -0,0 +1,44 @@ + + + + + 0 + 0 + 0 + RLIST STARTED (TSTTSKEL) STDATA + CLASS NAME + ----- ---- + STARTED TSTTSKEL + + LEVEL OWNER UNIVERSAL ACCESS YOUR ACCESS WARNING + ----- -------- ---------------- ----------- ------- + 00 ESWIFT NONE NONE NO + + INSTALLATION DATA + ----------------- + NONE + + APPLICATION DATA + ---------------- + NONE + + AUDITING + -------- + FAILURES(READ) + + NOTIFY + ------ + NO USER TO BE NOTIFIED + + STDATA INFORMATION + ------------------ + USER= + GROUP= + TRUSTED= YES + PRIVILEGED= NO + TRACE= NO + + + 0 + 0 + \ No newline at end of file diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index 4efa9571..f2e0712d 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -58,6 +58,9 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_DICTIONARY = get_sample( "extract_resource_result_bad_class_error.json" ) +TEST_EXTRACT_RESOURCE_RESULT_BASE_GENERIC_SUCCESS_XML = get_sample( + "extract_resource_result_base_generic_success.xml" +) # Delete Resource TEST_DELETE_RESOURCE_RESULT_SUCCESS_XML = get_sample( @@ -118,3 +121,187 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_RESOURCE_BASE_SUCCESS_LOG = get_sample("extract_resource_base_success.log") TEST_EXTRACT_RESOURCE_BASE_ERROR_LOG = get_sample("extract_resource_base_error.log") + +# ============================================================================ +# Class Administration +# ============================================================================ + +TEST_ADD_RESOURCE_CLASS_REQUEST_XML = get_sample("add_resource_class_request.xml") +TEST_ALTER_RESOURCE_CLASS_REQUEST_XML = get_sample("alter_resource_class_request.xml") +TEST_DELETE_RESOURCE_CLASS_REQUEST_XML = get_sample("delete_resource_class_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_CDTINFO_SUCCESS_XML = get_sample( + "extract_resource_result_base_cdtinfo_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_CDTINFO_ERROR_XML = get_sample( + "extract_resource_result_base_cdtinfo_error.xml" +) + +TEST_EXTRACT_RESOURCE_CLASS_PROFILE = { + "caseAllowed": "upper", + "defaultRacrouteReturnCode": 8, + "defaultUniversalAccess": None, + "validFirstCharacters": "alpha", + "genlist": "disallowed", + "generic": "allowed", + "groupingClassName": "", + "keyQualifiers": 0, + "manditoryAccessControlProcessing": "normal", + "maxLength": 246, + "maxLengthEntityx": 246, + "memberClassName": "", + "operations": None, + "validOtherCharacters": ["alpha", "numeric"], + "positNumber": 200, + "profilesAllowed": "yes", + "raclistAllowed": "allowed", + "securityLabelsRequired": None, + "sendEnfSignalOnProfileCreation": None, +} + + +TEST_ADD_RESOURCE_CLASS_REQUEST_TRAITS = { + "cdtinfo:case_allowed": "UPPER", + "cdtinfo:valid_first_characters": "ALPHA", + "cdtinfo:valid_other_characters": ["ALPHA", "NUMERIC"], + "cdtinfo:max_length": 246, + "cdtinfo:max_length_entityx": 246, + "cdtinfo:key_qualifiers": 0, + "cdtinfo:profiles_allowed": "YES", + "cdtinfo:posit_number": 200, + "cdtinfo:default_racroute_return_code": 8, + "cdtinfo:default_universal_access": "NONE", + "cdtinfo:raclist_allowed": "ALLOWED", +} + +TEST_ALTER_RESOURCE_CLASS_REQUEST_TRAITS = { + "cdtinfo:valid_first_characters": ["ALPHA", "NUMERIC"], + "cdtinfo:valid_other_characters": ["ALPHA"], + "cdtinfo:profiles_allowed": "NO", + "cdtinfo:default_racroute_return_code": 4, + "cdtinfo:default_universal_access": "READ", +} + +# ============================================================================ +# Custom Field Administration +# ============================================================================ + +TEST_ADD_CUSTOM_FIELD_REQUEST_XML = get_sample("add_custom_field_request.xml") +TEST_ALTER_CUSTOM_FIELD_REQUEST_XML = get_sample("alter_custom_field_request.xml") +TEST_DELETE_CUSTOM_FIELD_REQUEST_XML = get_sample("delete_custom_field_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_CFDEF_SUCCESS_XML = get_sample( + "extract_resource_result_base_cfdef_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_CFDEF_ERROR_XML = get_sample( + "extract_resource_result_base_cfdef_error.xml" +) + +TEST_EXTRACT_CUSTOM_FIELD_PROFILE = { + "customFieldDataType": "char", + "maxlength": None, + "maxNumericValue": None, + "minNumericValue": None, + "validFirstCharacters": "alpha", + "validOtherCharacters": "alpha", + "mixedCaseAllowed": None, + "helpText": ["favorite", "tv", "show"], +} + +TEST_ALTER_CUSTOM_FIELD_REQUEST_TRAITS = { + "cfdef:help_text": "Favorite TV Show", + "cfdef:valid_first_characters": "ALPHA", + "cfdef:valid_other_characters": "ALPHA", +} + +# ============================================================================ +# Started Task Administration +# ============================================================================ + +TEST_ADD_STARTED_TASK_REQUEST_XML = get_sample("add_started_task_request.xml") +TEST_ALTER_STARTED_TASK_REQUEST_XML = get_sample("alter_started_task_request.xml") +TEST_DELETE_STARTED_TASK_REQUEST_XML = get_sample("delete_started_task_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_STDATA_SUCCESS_XML = get_sample( + "extract_resource_result_base_stdata_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_STDATA_ERROR_XML = get_sample( + "extract_resource_result_base_stdata_error.xml" +) + +TEST_EXTRACT_STARTED_TASK_PROFILE = { + "user": "", + "group": "", + "trusted": "yes", + "privileged": None, + "trace": None, +} + +# ============================================================================ +# Kerberos Realm Administration +# ============================================================================ + +TEST_ADD_KERBEROS_REALM_REQUEST_XML = get_sample("add_kerberos_realm_request.xml") +TEST_ALTER_KERBEROS_REALM_REQUEST_XML = get_sample("alter_kerberos_realm_request.xml") +TEST_DELETE_KERBEROS_REALM_REQUEST_XML = get_sample("delete_kerberos_realm_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_KERB_SUCCESS_XML = get_sample( + "extract_resource_result_base_kerb_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_KERB_ERROR_XML = get_sample( + "extract_resource_result_base_kerb_error.xml" +) + +TEST_EXTRACT_KERBEROS_REALM_PROFILE = { + "keyEncryptionType": [ + "des", + "des3", + "desd", + "aes128", + "aes256", + "aes128sha2", + "aes256sha2", + ], + "checkAddresses": None, +} + +# ============================================================================ +# Signed Program Administration +# ============================================================================ + +TEST_ADD_SIGNED_PROGRAM_REQUEST_XML = get_sample("add_signed_program_request.xml") +TEST_ALTER_SIGNED_PROGRAM_REQUEST_XML = get_sample("alter_signed_program_request.xml") +TEST_DELETE_SIGNED_PROGRAM_REQUEST_XML = get_sample("delete_signed_program_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_SIGVER_SUCCESS_XML = get_sample( + "extract_resource_result_base_sigver_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_SIGVER_ERROR_XML = get_sample( + "extract_resource_result_base_sigver_error.xml" +) + +TEST_EXTRACT_SIGNED_PROGRAM_PROFILE = { + "signatureRequired": None, + "failProgramLoadCondition": "never", + "logSignatureVerificationEvents": "success", + "library": None, +} + +# ============================================================================ +# APPC Session Administration +# ============================================================================ + +TEST_ADD_APPC_SESSION_REQUEST_XML = get_sample("add_appc_session_request.xml") +TEST_ALTER_APPC_SESSION_REQUEST_XML = get_sample("alter_appc_session_request.xml") +TEST_DELETE_APPC_SESSION_REQUEST_XML = get_sample("delete_appc_session_request.xml") + +TEST_EXTRACT_RESOURCE_RESULT_BASE_SESSION_SUCCESS_XML = get_sample( + "extract_resource_result_base_session_success.xml" +) +TEST_EXTRACT_RESOURCE_RESULT_BASE_SESSION_ERROR_XML = get_sample( + "extract_resource_result_base_session_error.xml" +) + +# This segment requires additional logic that is not currently implemented. +# This will not be documented and the rest marked experimental +TEST_EXTRACT_APPC_SESSION_PROFILE = {} diff --git a/tests/resource/test_resource_result_parser.py b/tests/resource/test_resource_result_parser.py index 8c830103..525366ee 100644 --- a/tests/resource/test_resource_result_parser.py +++ b/tests/resource/test_resource_result_parser.py @@ -63,6 +63,19 @@ def test_resource_admin_throws_error_on_add_existing_profile( + f"'{profile_name}' already exists as a profile in the '{class_name}' class.", ) + def test_resource_admin_avoids_error_on_add_covered_profile( + self, + call_racf_mock: Mock, + ): + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_GENERIC_SUCCESS_XML, + TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_XML, + ] + self.assertEqual( + self.resource_admin.add("TESTING", "ELIJTEST"), + TestResourceConstants.TEST_ADD_RESOURCE_RESULT_SUCCESS_DICTIONARY, + ) + # Error: bad Entity Name ELIXTEST def test_resource_admin_can_parse_add_resource_error_xml( self, @@ -122,6 +135,29 @@ def test_resource_admin_throws_error_on_alter_new_profile( + f"'{profile_name}' does not exist as a profile in the '{class_name}' class.", ) + def test_resource_admin_throws_error_on_alter_covered_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "TESTING" + class_name = "ELIJTEST" + call_racf_mock.side_effect = [ + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_GENERIC_SUCCESS_XML, + TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.resource_admin.alter( + profile_name, + class_name, + traits=TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a profile in the '{class_name}' class.", + ) + # Error: bad Universal Access ALL def test_resource_admin_can_parse_alter_resource_error_xml( self, diff --git a/tests/resource/test_resource_sub_function_extracts.py b/tests/resource/test_resource_sub_function_extracts.py new file mode 100644 index 00000000..e68b46c0 --- /dev/null +++ b/tests/resource/test_resource_sub_function_extracts.py @@ -0,0 +1,170 @@ +"""Test general resource profile setter functions.""" + +import unittest +from unittest.mock import Mock, patch + +import __init__ + +import tests.resource.test_resource_constants as TestResourceConstants +from pyracf import ResourceAdmin, SecurityRequestError +from pyracf.common.irrsmo00 import IRRSMO00 + +# Resolves F401 +__init__ + + +@patch("pyracf.common.irrsmo00.IRRSMO00.call_racf") +class TestResourceSubFunctionExtracts(unittest.TestCase): + maxDiff = None + IRRSMO00.__init__ = Mock(return_value=None) + resource_admin = ResourceAdmin() + + # ============================================================================ + # Class Administration + # ============================================================================ + def test_resource_admin_extract_resource_class_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_CDTINFO_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_resource_class("SHELCITY"), + TestResourceConstants.TEST_EXTRACT_RESOURCE_CLASS_PROFILE, + ) + + def test_resource_admin_extract_resource_class_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_CDTINFO_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_resource_class("SHELCITY") + + # ============================================================================ + # Started Task Administration + # ============================================================================ + def test_resource_admin_build_extract_started_task_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_STDATA_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_started_task("TSTTSKEL"), + TestResourceConstants.TEST_EXTRACT_STARTED_TASK_PROFILE, + ) + + def test_resource_admin_build_extract_started_task_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_STDATA_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_started_task("TSTTSKEL") + + # ============================================================================ + # Custom Field Administration + # ============================================================================ + def test_resource_admin_build_extract_custom_field_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_CFDEF_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_custom_field("TVSHOW", "user"), + TestResourceConstants.TEST_EXTRACT_CUSTOM_FIELD_PROFILE, + ) + + def test_resource_admin_build_extract_custom_field_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_CFDEF_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_custom_field("TVSHOW", "user") + + # ============================================================================ + # Kerberos Realm Administration + # ============================================================================ + def test_resource_admin_build_extract_kerberos_realm_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_KERB_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_kerberos_realm("TSTREALM"), + TestResourceConstants.TEST_EXTRACT_KERBEROS_REALM_PROFILE, + ) + + def test_resource_admin_build_extract_kerberos_realm_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_KERB_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_kerberos_realm("TSTREALM") + + # ============================================================================ + # Signed Program Administration + # ============================================================================ + def test_resource_admin_build_extract_signed_program_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SIGVER_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_signed_program("TESTPRGM"), + TestResourceConstants.TEST_EXTRACT_SIGNED_PROGRAM_PROFILE, + ) + + def test_resource_admin_build_extract_signed_program_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SIGVER_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_signed_program("TESTPRGM") + + # ============================================================================ + # APPC Session Administration + # ============================================================================ + def test_resource_admin_build_extract_appc_session_returns_valid_on_success( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SESSION_SUCCESS_XML + ) + self.assertEqual( + self.resource_admin.extract_appc_session("TSTNET", "TSTLOCLU", "TSTPRTLU"), + TestResourceConstants.TEST_EXTRACT_APPC_SESSION_PROFILE, + ) + + def test_resource_admin_build_extract_appc_session_raises_exception_when_extract_fails( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SESSION_ERROR_XML + ) + with self.assertRaises(SecurityRequestError): + self.resource_admin.extract_appc_session("TSTNET", "TSTLOCLU", "TSTPRTLU") diff --git a/tests/resource/test_resource_sub_function_requests.py b/tests/resource/test_resource_sub_function_requests.py new file mode 100644 index 00000000..cfd48189 --- /dev/null +++ b/tests/resource/test_resource_sub_function_requests.py @@ -0,0 +1,163 @@ +"""Test general resource profile setter functions.""" + +import unittest +from unittest.mock import Mock + +import __init__ + +import tests.resource.test_resource_constants as TestResourceConstants +from pyracf import ResourceAdmin +from pyracf.common.irrsmo00 import IRRSMO00 + +# Resolves F401 +__init__ + + +class TestResourceSubFunctionRequests(unittest.TestCase): + maxDiff = None + IRRSMO00.__init__ = Mock(return_value=None) + resource_admin = ResourceAdmin(generate_requests_only=True) + + # ============================================================================ + # Class Administration + # ============================================================================ + def test_resource_admin_build_add_resource_class_request(self): + result = self.resource_admin.add_resource_class( + "SHELCITY", TestResourceConstants.TEST_ADD_RESOURCE_CLASS_REQUEST_TRAITS + ) + self.assertEqual( + result, TestResourceConstants.TEST_ADD_RESOURCE_CLASS_REQUEST_XML + ) + + def test_resource_admin_build_alter_resource_class_request(self): + result = self.resource_admin.alter_resource_class( + "SHELCITY", TestResourceConstants.TEST_ALTER_RESOURCE_CLASS_REQUEST_TRAITS + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_RESOURCE_CLASS_REQUEST_XML + ) + + def test_resource_admin_build_delete_resource_class_request(self): + result = self.resource_admin.delete_resource_class("SHELCITY") + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_RESOURCE_CLASS_REQUEST_XML + ) + + # ============================================================================ + # Started Task Administration + # ============================================================================ + def test_resource_admin_build_add_started_task_request(self): + result = self.resource_admin.add_started_task("TSTTSKEL") + self.assertEqual( + result, TestResourceConstants.TEST_ADD_STARTED_TASK_REQUEST_XML + ) + + def test_resource_admin_build_alter_started_task_request(self): + result = self.resource_admin.alter_started_task( + "TSTTSKEL", {"stdata:trusted": True} + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_STARTED_TASK_REQUEST_XML + ) + + def test_resource_admin_build_delete_started_task_request(self): + result = self.resource_admin.delete_started_task("TSTTSKEL") + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_STARTED_TASK_REQUEST_XML + ) + + # ============================================================================ + # Custom Field Administration + # ============================================================================ + def test_resource_admin_build_add_custom_field_request(self): + result = self.resource_admin.add_custom_field("TVSHOW", "user") + self.assertEqual( + result, TestResourceConstants.TEST_ADD_CUSTOM_FIELD_REQUEST_XML + ) + + def test_resource_admin_build_alter_custom_field_request(self): + result = self.resource_admin.alter_custom_field( + "TVSHOW", + "user", + traits=TestResourceConstants.TEST_ALTER_CUSTOM_FIELD_REQUEST_TRAITS, + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_CUSTOM_FIELD_REQUEST_XML + ) + + def test_resource_admin_build_delete_custom_field_request(self): + result = self.resource_admin.delete_custom_field("TVSHOW", "user") + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_CUSTOM_FIELD_REQUEST_XML + ) + + # ============================================================================ + # Kerberos Realm Administration + # ============================================================================ + def test_resource_admin_build_add_kerberos_realm_request(self): + result = self.resource_admin.add_kerberos_realm("TSTREALM") + self.assertEqual( + result, TestResourceConstants.TEST_ADD_KERBEROS_REALM_REQUEST_XML + ) + + def test_resource_admin_build_alter_kerberos_realm_request(self): + result = self.resource_admin.alter_kerberos_realm( + "TSTREALM", traits={"kerb:encryption_algorithms": "AES128"} + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_KERBEROS_REALM_REQUEST_XML + ) + + def test_resource_admin_build_delete_kerberos_realm_request(self): + result = self.resource_admin.delete_kerberos_realm("TSTREALM") + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_KERBEROS_REALM_REQUEST_XML + ) + + # ============================================================================ + # Signed Program Administration + # ============================================================================ + def test_resource_admin_build_add_signed_program_request(self): + result = self.resource_admin.add_signed_program("TESTPRGM") + self.assertEqual( + result, TestResourceConstants.TEST_ADD_SIGNED_PROGRAM_REQUEST_XML + ) + + def test_resource_admin_build_alter_signed_program_request(self): + result = self.resource_admin.alter_signed_program( + "TESTPRGM", traits={"sigver:log_signature_verification_events": "SUCCESS"} + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_SIGNED_PROGRAM_REQUEST_XML + ) + + def test_resource_admin_build_delete_signed_program_request(self): + result = self.resource_admin.delete_signed_program("TESTPRGM") + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_SIGNED_PROGRAM_REQUEST_XML + ) + + # ============================================================================ + # APPC Session Administration + # ============================================================================ + def test_resource_admin_build_add_appc_session_request(self): + result = self.resource_admin.add_appc_session("TSTNET", "TSTLOCLU", "TSTPRTLU") + self.assertEqual( + result, TestResourceConstants.TEST_ADD_APPC_SESSION_REQUEST_XML + ) + + def test_resource_admin_build_alter_appc_session_request(self): + result = self.resource_admin.alter_appc_session( + "TSTNET", "TSTLOCLU", "TSTPRTLU", traits={"session:locked": True} + ) + self.assertEqual( + result, TestResourceConstants.TEST_ALTER_APPC_SESSION_REQUEST_XML + ) + + def test_resource_admin_build_delete_appc_session_request(self): + result = self.resource_admin.delete_appc_session( + "TSTNET", "TSTLOCLU", "TSTPRTLU" + ) + self.assertEqual( + result, TestResourceConstants.TEST_DELETE_APPC_SESSION_REQUEST_XML + ) diff --git a/tests/test_runner.py b/tests/test_runner.py index 8b240d9c..e0b1aab8 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -30,6 +30,12 @@ from tests.resource.test_resource_request_builder import TestResourceRequestBuilder from tests.resource.test_resource_result_parser import TestResourceResultParser from tests.resource.test_resource_setters import TestResourceSetters +from tests.resource.test_resource_sub_function_extracts import ( + TestResourceSubFunctionExtracts, +) +from tests.resource.test_resource_sub_function_requests import ( + TestResourceSubFunctionRequests, +) from tests.setropts.test_setropts_debug_logging import TestSetroptsDebugLogging from tests.setropts.test_setropts_getters import TestSetroptsGetters from tests.setropts.test_setropts_request_builder import TestSetroptsRequestBuilder @@ -68,6 +74,8 @@ def __test_suite() -> unittest.TestSuite: TestResourceGetters, TestResourceSetters, TestResourceDebugLogging, + TestResourceSubFunctionRequests, + TestResourceSubFunctionExtracts, TestGroupResultParser, TestGroupRequestBuilder, TestGroupGetters, From c53fdcc5f93aed5cc1c2eb149c1457a76737ec7a Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 11:53:36 -0400 Subject: [PATCH 62/72] Comments and Name Changes Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 3 +++ pyracf/resource/resource_admin.py | 8 ++++---- tests/resource/test_resource_constants.py | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index e4c901b3..7eb336be 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -13,6 +13,9 @@ typedef struct { char str[8]; } VarStr_T; +// This function changes any null character not preceded by '>' to whitespace +// This works around an issue with IRRSMO00 treating whitespace as null characters +// which led to premature string termination void null_byte_fix(char* str, unsigned int str_len) { for (int i = 1; i < str_len; i++){ if (str[i] == 0) { diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index b62fb5be..9e0d5d4e 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -59,8 +59,8 @@ def __init__( "cdtinfo:case_allowed": "case", "cdtinfo:default_racroute_return_code": "defaultrc", "cdtinfo:valid_first_characters": "first", - "cdtinfo:generic": "generic", - "cdtinfo:genlist": "genlist", + "cdtinfo:generic_profile_checking": "racf:generic", + "cdtinfo:generic_profile_sharing": "racf:genlist", "cdtinfo:grouping_class_name": "grouping", "cdtinfo:key_qualifiers": "keyqual", "cdtinfo:manditory_access_control_processing": "macprocessing", @@ -185,8 +185,8 @@ def __init__( "case": "caseAllowed", "defaultrc": "defaultRacrouteReturnCode", "first": "validFirstCharacters", - "generic": "generic", - "genlist": "genlist", + "generic": "genericProfileChecking", + "genlist": "genericProfileSharing", "group": "groupingClassName", "keyqualifiers": "keyQualifiers", "macprocessing": "manditoryAccessControlProcessing", diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index f2e0712d..b23c189e 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -142,8 +142,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "defaultRacrouteReturnCode": 8, "defaultUniversalAccess": None, "validFirstCharacters": "alpha", - "genlist": "disallowed", - "generic": "allowed", + "genericProfileSharing": "disallowed", + "genericProfileChecking": "allowed", "groupingClassName": "", "keyQualifiers": 0, "manditoryAccessControlProcessing": "normal", From c8deb71cc7f1f30d88cb99b77438e4df08081d72 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 13:02:40 -0400 Subject: [PATCH 63/72] Change wording and naming Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 6 +++--- tests/resource/test_resource_sub_function_extracts.py | 2 +- tests/resource/test_resource_sub_function_requests.py | 2 +- tests/test_runner.py | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index 7eb336be..b22f6623 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -13,9 +13,9 @@ typedef struct { char str[8]; } VarStr_T; -// This function changes any null character not preceded by '>' to whitespace -// This works around an issue with IRRSMO00 treating whitespace as null characters -// which led to premature string termination +// This function changes any null character not preceded by '>' to a blank character. +// This works around an issue with our expectations of values in the response string +// returned from IRRSMO00 which led to premature string termination. void null_byte_fix(char* str, unsigned int str_len) { for (int i = 1; i < str_len; i++){ if (str[i] == 0) { diff --git a/tests/resource/test_resource_sub_function_extracts.py b/tests/resource/test_resource_sub_function_extracts.py index e68b46c0..2f4787aa 100644 --- a/tests/resource/test_resource_sub_function_extracts.py +++ b/tests/resource/test_resource_sub_function_extracts.py @@ -14,7 +14,7 @@ @patch("pyracf.common.irrsmo00.IRRSMO00.call_racf") -class TestResourceSubFunctionExtracts(unittest.TestCase): +class TestResourceSubfunctionExtracts(unittest.TestCase): maxDiff = None IRRSMO00.__init__ = Mock(return_value=None) resource_admin = ResourceAdmin() diff --git a/tests/resource/test_resource_sub_function_requests.py b/tests/resource/test_resource_sub_function_requests.py index cfd48189..e99d80a7 100644 --- a/tests/resource/test_resource_sub_function_requests.py +++ b/tests/resource/test_resource_sub_function_requests.py @@ -13,7 +13,7 @@ __init__ -class TestResourceSubFunctionRequests(unittest.TestCase): +class TestResourceSubfunctionRequests(unittest.TestCase): maxDiff = None IRRSMO00.__init__ = Mock(return_value=None) resource_admin = ResourceAdmin(generate_requests_only=True) diff --git a/tests/test_runner.py b/tests/test_runner.py index e0b1aab8..e06697a6 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -31,10 +31,10 @@ from tests.resource.test_resource_result_parser import TestResourceResultParser from tests.resource.test_resource_setters import TestResourceSetters from tests.resource.test_resource_sub_function_extracts import ( - TestResourceSubFunctionExtracts, + TestResourceSubfunctionExtracts, ) from tests.resource.test_resource_sub_function_requests import ( - TestResourceSubFunctionRequests, + TestResourceSubfunctionRequests, ) from tests.setropts.test_setropts_debug_logging import TestSetroptsDebugLogging from tests.setropts.test_setropts_getters import TestSetroptsGetters @@ -74,8 +74,8 @@ def __test_suite() -> unittest.TestSuite: TestResourceGetters, TestResourceSetters, TestResourceDebugLogging, - TestResourceSubFunctionRequests, - TestResourceSubFunctionExtracts, + TestResourceSubfunctionRequests, + TestResourceSubfunctionExtracts, TestGroupResultParser, TestGroupRequestBuilder, TestGroupGetters, From f66964d96a5202c1c6eaebb0dd46ba64b0eeb219 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 13:11:44 -0400 Subject: [PATCH 64/72] Add Dataset Covered Profile Testing Signed-off-by: Elijah Swift --- tests/data_set/test_data_set_result_parser.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/data_set/test_data_set_result_parser.py b/tests/data_set/test_data_set_result_parser.py index 27c0070b..c4417d35 100644 --- a/tests/data_set/test_data_set_result_parser.py +++ b/tests/data_set/test_data_set_result_parser.py @@ -65,6 +65,22 @@ def test_data_set_admin_thows_error_on_add_existing_data_set_profile( + f"'{self.data_set_admin._profile_type}' profile.", ) + def test_dataset_admin_avoids_error_on_add_covered_profile( + self, + call_racf_mock: Mock, + ): + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_XML, + ] + self.assertEqual( + self.data_set_admin.add( + "ESWIFT.TEST.T1136242.P3020470", + traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, + ), + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_DICTIONARY, + ) + # Error in command, ESWIFTTESTT1136242P3020470 is not a valid DATASET def test_data_set_admin_can_parse_add_data_set_error_xml( self, @@ -125,6 +141,28 @@ def test_data_set_admin_thows_error_on_alter_new_data_set_profile( + f"'{self.data_set_admin._profile_type}' profile.", ) + def test_dataset_admin_throws_error_on_alter_covered_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "ESWIFT.TEST.T1136242.P3020470" + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_GENERIC_BASE_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, + ] + with self.assertRaises(AlterOperationError) as exception: + self.data_set_admin.alter( + profile_name, + traits=TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS, + ) + self.assertEqual( + exception.exception.message, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a " + + f"'{self.data_set_admin._profile_type}' profile.", + ) + # Error in environment, ESWIFT.TEST.T1136242.P3020470 data set does not exist def test_data_set_admin_can_parse_alter_data_set_error_xml( self, From 1da9b13ff74ec4dfcb466f5973df8c79cf6749e3 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 13:14:38 -0400 Subject: [PATCH 65/72] Name and Doc Changes Signed-off-by: Elijah Swift --- pyracf/common/irrsmo00.c | 5 +++-- ...ion_extracts.py => test_resource_subfunction_extracts.py} | 0 ...ion_requests.py => test_resource_subfunction_requests.py} | 0 tests/test_runner.py | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) rename tests/resource/{test_resource_sub_function_extracts.py => test_resource_subfunction_extracts.py} (100%) rename tests/resource/{test_resource_sub_function_requests.py => test_resource_subfunction_requests.py} (100%) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index b22f6623..2cff3cff 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -14,8 +14,9 @@ typedef struct { } VarStr_T; // This function changes any null character not preceded by '>' to a blank character. -// This works around an issue with our expectations of values in the response string -// returned from IRRSMO00 which led to premature string termination. +// This is a workaround for an issue where the profile data embedded in response xml +// returned by IRROSMO00 sometimes includes null characters instead of properly +// encoded text, which causes the returned xml to be truncated. void null_byte_fix(char* str, unsigned int str_len) { for (int i = 1; i < str_len; i++){ if (str[i] == 0) { diff --git a/tests/resource/test_resource_sub_function_extracts.py b/tests/resource/test_resource_subfunction_extracts.py similarity index 100% rename from tests/resource/test_resource_sub_function_extracts.py rename to tests/resource/test_resource_subfunction_extracts.py diff --git a/tests/resource/test_resource_sub_function_requests.py b/tests/resource/test_resource_subfunction_requests.py similarity index 100% rename from tests/resource/test_resource_sub_function_requests.py rename to tests/resource/test_resource_subfunction_requests.py diff --git a/tests/test_runner.py b/tests/test_runner.py index e06697a6..6253f828 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -30,10 +30,10 @@ from tests.resource.test_resource_request_builder import TestResourceRequestBuilder from tests.resource.test_resource_result_parser import TestResourceResultParser from tests.resource.test_resource_setters import TestResourceSetters -from tests.resource.test_resource_sub_function_extracts import ( +from tests.resource.test_resource_subfunction_extracts import ( TestResourceSubfunctionExtracts, ) -from tests.resource.test_resource_sub_function_requests import ( +from tests.resource.test_resource_subfunction_requests import ( TestResourceSubfunctionRequests, ) from tests.setropts.test_setropts_debug_logging import TestSetroptsDebugLogging From e8fe0f6653e905e1ab2c02f30c6d1b565cc0014f Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 2 Nov 2023 14:18:30 -0400 Subject: [PATCH 66/72] Fix extra messages in profile extract bug. Signed-off-by: Leonard Carcaramo --- pyracf/common/security_result.py | 71 +++++++++++-------- tests/user/test_user_constants.py | 6 ++ tests/user/test_user_result_parser.py | 12 ++++ ...ct_user_result_extra_messages_success.json | 56 +++++++++++++++ ...act_user_result_extra_messages_success.xml | 35 +++++++++ 5 files changed, 152 insertions(+), 28 deletions(-) create mode 100644 tests/user/user_result_samples/extract_user_result_extra_messages_success.json create mode 100644 tests/user/user_result_samples/extract_user_result_extra_messages_success.xml diff --git a/pyracf/common/security_result.py b/pyracf/common/security_result.py index 90933827..dba11ae2 100644 --- a/pyracf/common/security_result.py +++ b/pyracf/common/security_result.py @@ -1,5 +1,6 @@ """Generic Security Result Parser.""" +import re from xml.etree.ElementTree import Element # Only used for type hints. import defusedxml.ElementTree as XMLParser @@ -15,58 +16,72 @@ def __init__(self, result_xml: str) -> None: def __extract_results(self) -> None: """Extract XML results into a dictionary.""" - self.definition = self.__result[0] - self.definition.attrib["requestId"] = self.definition.attrib["requestid"] - del self.definition.attrib["requestid"] - definition_tag = self.__to_pascal_case(self.definition.tag.split("}")[-1]) + self.__definition = self.__result[0] + return_code = int(self.__result[1].text) + reason_code = int(self.__result[2].text) + self.__definition.attrib["requestId"] = self.__definition.attrib["requestid"] + del self.__definition.attrib["requestid"] + definition_tag = self.__to_pascal_case(self.__definition.tag.split("}")[-1]) self.__result_dictionary["securityResult"][ definition_tag - ] = self.definition.attrib - self.definition_dictionary = self.__result_dictionary["securityResult"][ + ] = self.__definition.attrib + self.__definition_dictionary = self.__result_dictionary["securityResult"][ definition_tag ] + filter_out_extra_messages = False + if return_code == 0 and self.__definition_dictionary["operation"] == "listdata": + filter_out_extra_messages = True try: - if self.definition[0].tag.split("}")[-1] == "info": + if self.__definition[0].tag.split("}")[-1] == "info": self.__extract_info() - if self.definition[0].tag.split("}")[-1] == "error": + if self.__definition[0].tag.split("}")[-1] == "error": self.__extract_error() else: - self.__extract_commands() + self.__extract_commands(filter_out_extra_messages) except IndexError: # Index Error indicates that there is no # additional information to extract from the definition. pass - return_code = self.__result[1] - self.__result_dictionary["securityResult"]["returnCode"] = int(return_code.text) - reason_code = self.__result[2] - self.__result_dictionary["securityResult"]["reasonCode"] = int(reason_code.text) + self.__result_dictionary["securityResult"]["returnCode"] = return_code + self.__result_dictionary["securityResult"]["reasonCode"] = reason_code def __extract_info(self) -> None: """Extract info section from XML into a list.""" - self.definition_dictionary["info"] = [] - info = self.definition_dictionary["info"] - while self.definition[0].tag.split("}")[-1] == "info": - item = self.definition[0] + self.__definition_dictionary["info"] = [] + info = self.__definition_dictionary["info"] + while self.__definition[0].tag.split("}")[-1] == "info": + item = self.__definition[0] if item.tag.split("}")[-1] != "info": return info.append(item.text) - self.definition.remove(item) + self.__definition.remove(item) - def __extract_commands(self) -> None: + def __extract_commands(self, filter_out_extra_messages: bool) -> None: """Extract commands section from XML into a list.""" - self.definition_dictionary["commands"] = [] - commands = self.definition_dictionary["commands"] - for command in self.definition: - self.__extract_command(commands, command) + self.__definition_dictionary["commands"] = [] + commands = self.__definition_dictionary["commands"] + for command in self.__definition: + self.__extract_command(commands, command, filter_out_extra_messages) - def __extract_command(self, commands: dict, command: Element) -> None: + def __extract_command( + self, + commands: dict, + command: Element, + filter_out_extra_messages: bool, + ) -> None: command_dictionary = {} commands.append(command_dictionary) + message_id_regex = r"[A-Z]{3}[0-9]{5}[A-Z]" for item in command: item_tag = self.__to_pascal_case(item.tag.split("}")[-1]) if item_tag == "message": if "messages" not in command_dictionary: command_dictionary["messages"] = [] + if item.text: + if filter_out_extra_messages and re.match( + message_id_regex, item.text + ): + continue command_dictionary["messages"].append(item.text) else: try: @@ -76,14 +91,14 @@ def __extract_command(self, commands: dict, command: Element) -> None: def __extract_error(self) -> None: """Extract error section from XML into a dictionary.""" - self.definition_dictionary["error"] = {} - error = self.definition[0] + self.__definition_dictionary["error"] = {} + error = self.__definition[0] for item in error: item_tag = self.__to_pascal_case(item.tag.split("}")[-1]) try: - self.definition_dictionary["error"][item_tag] = int(item.text) + self.__definition_dictionary["error"][item_tag] = int(item.text) except ValueError: - self.definition_dictionary["error"][item_tag] = item.text + self.__definition_dictionary["error"][item_tag] = item.text def __to_pascal_case(self, key: str) -> str: """Convert result dictionary keys to pascal case.""" diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index e4d05852..d5d4cb21 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -115,6 +115,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY = get_sample( "extract_user_result_base_omvs_tso_revoke_resume.json" ) +TEST_EXTRACT_USER_RESULT_EXTRA_MESSAGES_SUCCESS_XML = get_sample( + "extract_user_result_extra_messages_success.xml" +) +TEST_EXTRACT_USER_RESULT_EXTRA_MESSAGES_SUCCESS_DICTIONARY = get_sample( + "extract_user_result_extra_messages_success.json" +) # Delete User TEST_DELETE_USER_RESULT_SUCCESS_XML = get_sample("delete_user_result_success.xml") diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index 64cb6739..c7789f98 100644 --- a/tests/user/test_user_result_parser.py +++ b/tests/user/test_user_result_parser.py @@ -196,6 +196,18 @@ def test_user_admin_can_parse_extract_user_and_ignore_command_audit_trail_xml( TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY, ) + def test_user_admin_can_parse_extract_user_and_ignore_extra_messages_on_succes_xml( + self, + call_racf_mock: Mock, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_EXTRA_MESSAGES_SUCCESS_XML + ) + self.assertEqual( + self.user_admin.extract("squidwrd", segments=["omvs", "tso", "ovm"]), + TestUserConstants.TEST_EXTRACT_USER_RESULT_EXTRA_MESSAGES_SUCCESS_DICTIONARY, + ) + def test_user_admin_can_parse_extract_user_base_omvs_tso_revoke_resume_success_xml( self, call_racf_mock: Mock, diff --git a/tests/user/user_result_samples/extract_user_result_extra_messages_success.json b/tests/user/user_result_samples/extract_user_result_extra_messages_success.json new file mode 100644 index 00000000..fec77e9c --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_extra_messages_success.json @@ -0,0 +1,56 @@ +{ + "securityResult": { + "user": { + "name": "SQUIDWRD", + "operation": "listdata", + "requestId": "UserRequest", + "commands": [ + { + "safReturnCode": 0, + "returnCode": 0, + "reasonCode": 0, + "image": "LISTUSER SQUIDWRD OMVS TSO OVM ", + "profiles": [ + { + "base": { + "user": "squidwrd", + "name": "squidward", + "owner": "leonard", + "created": "4/4/2023", + "defaultGroup": "sys1", + "passwordDate": null, + "passwordInterval": 186, + "passphraseDate": null, + "attributes": [], + "revokeDate": null, + "resumeDate": null, + "lastAccess": "4/4/2023 12:55 PM", + "classAuthorizations": [], + "logonAllowedDays": "anyday", + "logonAllowedTime": "anytime", + "groups": { + "SYS1": { + "auth": "use", + "connectOwner": "leonard", + "connectDate": "4/4/2023", + "connects": 0, + "uacc": null, + "lastConnect": null, + "connectAttributes": [], + "revokeDate": null, + "resumeDate": null + } + }, + "securityLevel": null, + "categoryAuthorization": null, + "securityLabel": null + } + } + ] + } + ] + }, + "returnCode": 0, + "reasonCode": 0 + } +} \ No newline at end of file diff --git a/tests/user/user_result_samples/extract_user_result_extra_messages_success.xml b/tests/user/user_result_samples/extract_user_result_extra_messages_success.xml new file mode 100644 index 00000000..1927a241 --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_extra_messages_success.xml @@ -0,0 +1,35 @@ + + + + + 0 + 0 + 0 + LISTUSER SQUIDWRD OMVS TSO OVM + USER=SQUIDWRD NAME=SQUIDWARD OWNER=LEONARD CREATED=23.094 + DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A + ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + LAST-ACCESS=23.094/12:55:37 + CLASS AUTHORIZATIONS=NONE + NO-INSTALLATION-DATA + NO-MODEL-NAME + LOGON ALLOWED (DAYS) (TIME) + --------------------------------------------- + ANYDAY ANYTIME + GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.094 + CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN + CONNECT ATTRIBUTES=NONE + REVOKE DATE=NONE RESUME DATE=NONE + SECURITY-LEVEL=NONE SPECIFIED + CATEGORY-AUTHORIZATION + NONE SPECIFIED + SECURITY-LABEL=NONE SPECIFIED + IRR52021I You are not authorized to view OMVS segments. + IRR52021I You are not authorized to view TSO segments. + IRR52021I You are not authorized to view OVM segments. + + + 0 + 0 + \ No newline at end of file From 48c6206c0ef2cfb70b3ad440a9bbc5aa7b7b14f9 Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 2 Nov 2023 14:37:26 -0400 Subject: [PATCH 67/72] Fix debug logging test case. Signed-off-by: Leonard Carcaramo --- tests/user/test_user_debug_logging.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index 346eb239..c3b27d08 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -247,17 +247,13 @@ def test_alter_user_request_debug_log_password_xml_tags_not_redacted_on_error( with contextlib.redirect_stdout(stdout): try: error_traits = dict( - TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD + TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE ) error_traits["omvs:uid"] = 90000000000 self.user_admin.alter( "squidwrd", traits=error_traits, ) - self.user_admin.alter( - "squidwrd", - traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, - ) except SecurityRequestError: pass error_log = self.ansi_escape.sub("", stdout.getvalue()) From 4b09481dd9496aee7c067fc9f9f17010a4656d9e Mon Sep 17 00:00:00 2001 From: Leonard Carcaramo Date: Thu, 2 Nov 2023 14:40:21 -0400 Subject: [PATCH 68/72] Cleanup. Signed-off-by: Leonard Carcaramo --- pyracf/common/irrsmo00.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyracf/common/irrsmo00.c b/pyracf/common/irrsmo00.c index 2cff3cff..8ebdc8d4 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -14,7 +14,7 @@ typedef struct { } VarStr_T; // This function changes any null character not preceded by '>' to a blank character. -// This is a workaround for an issue where the profile data embedded in response xml +// This is a workaround for an issue where profile data embedded in response xml // returned by IRROSMO00 sometimes includes null characters instead of properly // encoded text, which causes the returned xml to be truncated. void null_byte_fix(char* str, unsigned int str_len) { From 15f2c7a1b9406e62d96ed0735bb6ed4e72106530 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 18:35:09 -0400 Subject: [PATCH 69/72] Clear State before raising errors Add state clearing before raising SegmentError or SegmentTraitError. Add unit test for this (Unit test for SegmentTraitError includes extract to simulate functionality of add when generateRequestOnly is not set) Signed-off-by: Elijah Swift --- pyracf/common/security_admin.py | 2 ++ tests/user/test_user_request_builder.py | 43 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 8ff40445..d9eec027 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -269,6 +269,7 @@ def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: else: bad_segments.append(segment) if bad_segments: + self.__clear_state(SecurityRequest) raise SegmentError(bad_segments, self._profile_type) # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits @@ -287,6 +288,7 @@ def _build_segment_dictionaries(self, traits: dict) -> None: if not trait_valid: bad_traits.append(trait) if bad_traits: + self.__clear_state(SecurityRequest) raise SegmentTraitError(bad_traits, self._profile_type) # preserve segment traits for debug logging. diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 282d773c..083c718e 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,6 +140,30 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) + def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): + bad_trait = "omvs:bad_trait" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(SegmentTraitError) as exception: + user_admin.add( + "squidwrd", TestUserConstants.TEST_ADD_USER_REQUEST_BAD_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Unable to build Security Request.\n\n" + + f"'{bad_trait}' is not a known segment-trait " + + f"combination for '{self.user_admin._profile_type}'.\n", + ) + result = user_admin.extract("squidwrd", segments=["omvs"]) + self.assertEqual( + result, TestUserConstants.TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML + ) + result = self.user_admin.add( + "squidwrd", traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS + ) + self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_XML) + def test_user_admin_build_extract_request_with_bad_segment_name(self): bad_segment = "bad_segment" user_admin = UserAdmin( @@ -152,3 +176,22 @@ def test_user_admin_build_extract_request_with_bad_segment_name(self): "Unable to build Security Request.\n\n" + f"'{bad_segment}' is not a known segment for '{self.user_admin._profile_type}'.\n", ) + + def test_user_admin_cleans_up_after_build_extract_request_with_bad_segment_name( + self, + ): + bad_segment = "bad_segment" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(SegmentError) as exception: + user_admin.extract("squidwrd", segments=["tso", bad_segment]) + self.assertEqual( + exception.exception.message, + "Unable to build Security Request.\n\n" + + f"'{bad_segment}' is not a known segment for '{self.user_admin._profile_type}'.\n", + ) + result = user_admin.extract("squidwrd", segments=["omvs"]) + self.assertEqual( + result, TestUserConstants.TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML + ) From d6e0d3ed82e8c781ead3c09a1a519805fba7e2af Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 09:28:28 -0400 Subject: [PATCH 70/72] Function Rename Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 4 ++-- pyracf/common/security_admin.py | 4 ++-- pyracf/connection/connection_admin.py | 2 +- pyracf/data_set/data_set_admin.py | 10 +++++----- pyracf/group/group_admin.py | 10 +++++----- pyracf/resource/resource_admin.py | 10 +++++----- pyracf/setropts/setropts_admin.py | 4 ++-- pyracf/user/user_admin.py | 10 +++++----- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 40a129d7..46a13e4e 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -64,7 +64,7 @@ def permit( ) -> Union[dict, bytes]: """Create or change a permission""" traits["base:auth_id"] = auth_id - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments( access_request, alter=True @@ -81,7 +81,7 @@ def delete( ) -> Union[dict, bytes]: """Delete a permission.""" traits = {"base:auth_id": auth_id} - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) access_request = AccessRequest(resource, class_name, "del", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments(access_request) return self._make_request(access_request) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index d9eec027..00736756 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -260,7 +260,7 @@ def __validate_and_add_trait( self._trait_map[trait] = self._valid_segment_traits[segment][trait] return True - def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: + def _build_segment_dictionary(self, segments: List[str]) -> None: """Build segment dictionaries for profile extract.""" bad_segments = [] for segment in segments: @@ -274,7 +274,7 @@ def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits - def _build_segment_dictionaries(self, traits: dict) -> None: + def _build_segment_trait_dictionary(self, traits: dict) -> None: """Build segemnt dictionaries for each segment.""" bad_traits = [] for trait in traits: diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index 43049de5..2527118e 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -121,7 +121,7 @@ def take_away_group_access_attribute( # ============================================================================ def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: """Create or change a group connection.""" - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) connection_request = ConnectionRequest(userid, group, "set") self._add_traits_directly_to_request_xml_with_no_segments( connection_request, alter=True diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 41edc281..1995e5af 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -105,7 +105,7 @@ def add( ) -> Union[dict, bytes]: """Create a new data set profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request) return self._make_request(data_set_request) @@ -118,7 +118,7 @@ def add( except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH35003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request) return self._make_request(data_set_request) @@ -132,7 +132,7 @@ def alter( ) -> Union[dict, bytes]: """Alter an existing data set profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request, alter=True) return self._make_request(data_set_request, irrsmo00_precheck=True) @@ -144,7 +144,7 @@ def alter( raise AlterOperationError(data_set, self._profile_type) if not self._get_field(profile, "base", "name") == data_set.lower(): raise AlterOperationError(data_set, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request, alter=True) return self._make_request(data_set_request, irrsmo00_precheck=True) @@ -158,7 +158,7 @@ def extract( profile_only: bool = False, ) -> Union[dict, bytes]: """Extract a data set profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) data_set_request = DataSetRequest(data_set, "listdata", volume, generic) self._build_xml_segments(data_set_request, extract=True) result = self._extract_and_check_result(data_set_request) diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index daaf0ec6..63b22f7b 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -123,7 +123,7 @@ def set_ovm_gid(self, group: str, gid: int) -> Union[dict, bytes]: def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new group.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request) return self._make_request(group_request) @@ -132,7 +132,7 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH51003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request) return self._make_request(group_request) @@ -141,7 +141,7 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) return self._make_request(group_request, irrsmo00_precheck=True) @@ -149,7 +149,7 @@ def alter(self, group: str, traits: dict) -> Union[dict, bytes]: self.extract(group) except SecurityRequestError: raise AlterOperationError(group, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) return self._make_request(group_request, irrsmo00_precheck=True) @@ -158,7 +158,7 @@ def extract( self, group: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a group's profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) group_request = GroupRequest(group, "listdata") self._build_xml_segments(group_request, extract=True) result = self._extract_and_check_result(group_request) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 9e0d5d4e..f42108d1 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -487,7 +487,7 @@ def add( ) -> Union[dict, bytes]: """Create a new general resource profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request) return self._make_request(profile_request) @@ -498,7 +498,7 @@ def add( except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH13003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request) return self._make_request(profile_request) @@ -506,7 +506,7 @@ def add( def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, bytes]: """Alter an existing general resource profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) return self._make_request(profile_request, irrsmo00_precheck=True) @@ -516,7 +516,7 @@ def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, byt raise AlterOperationError(resource, class_name) if not self._get_field(profile, "base", "name") == resource.lower(): raise AlterOperationError(resource, class_name) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) return self._make_request(profile_request, irrsmo00_precheck=True) @@ -529,7 +529,7 @@ def extract( profile_only: bool = False, ) -> Union[dict, bytes]: """Extract a general resource profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) resource_request = ResourceRequest(resource, class_name, "listdata") self._build_xml_segments(resource_request, extract=True) result = self._extract_and_check_result(resource_request) diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 12fcd952..0b3230ab 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -313,7 +313,7 @@ def remove_raclist_classes( # ============================================================================ def list_racf_options(self, options_only: bool = False) -> Union[dict, bytes]: """List RACF options.""" - self._build_segment_dictionaries({"base:list": True}) + self._build_segment_trait_dictionary({"base:list": True}) setropts_request = SetroptsRequest() self._add_traits_directly_to_request_xml_with_no_segments(setropts_request) result = self._extract_and_check_result(setropts_request) @@ -323,7 +323,7 @@ def list_racf_options(self, options_only: bool = False) -> Union[dict, bytes]: def alter(self, options: dict = {}) -> Union[dict, bytes]: """Update RACF options.""" - self._build_segment_dictionaries(options) + self._build_segment_trait_dictionary(options) setropts_request = SetroptsRequest() self._add_traits_directly_to_request_xml_with_no_segments( setropts_request, alter=True diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index a126c58e..beba75cd 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -769,7 +769,7 @@ def set_tso_data_set_allocation_unit( def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new user.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request) return self._make_request(user_request) @@ -778,7 +778,7 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH30001I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request) return self._make_request(user_request) @@ -787,7 +787,7 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: """Alter an existing user.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) return self._make_request(user_request, irrsmo00_precheck=True) @@ -795,7 +795,7 @@ def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: self.extract(userid) except SecurityRequestError: raise AlterOperationError(userid, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) return self._make_request(user_request, irrsmo00_precheck=True) @@ -804,7 +804,7 @@ def extract( self, userid: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a user's profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) user_request = UserRequest(userid, "listdata") self._build_xml_segments(user_request, extract=True) result = self._extract_and_check_result(user_request) From 648fd0a236c4a0aad2a9c31335eb06b0d838c567 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 09:52:02 -0400 Subject: [PATCH 71/72] Update test_user_request_builder.py added comment to describe need for extract call in new test. Signed-off-by: Elijah Swift --- tests/user/test_user_request_builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 083c718e..da5b81bf 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,6 +140,9 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) +# Since this test uses GenerateRequestsOnly, the "Add" after the AddOperationError is returned +# does not begin with an "Extract" call. This is necessary to recreate the error, so an extra +# extract call was added to simulate this behavior. def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): bad_trait = "omvs:bad_trait" user_admin = UserAdmin( From eca4e7cb020a59f2965d73b47e9eec56c8a586f5 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 10:08:21 -0400 Subject: [PATCH 72/72] Update test_user_request_builder.py Signed-off-by: Elijah Swift --- tests/user/test_user_request_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index da5b81bf..7c7a15f5 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,9 +140,9 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) -# Since this test uses GenerateRequestsOnly, the "Add" after the AddOperationError is returned -# does not begin with an "Extract" call. This is necessary to recreate the error, so an extra -# extract call was added to simulate this behavior. + # Since this test uses generate_requests_only, the "Add" after the AddOperationError is + # returned does not begin with an "Extract" call. This is necessary to recreate the error, + # so an extra extract call was added to simulate this behavior. def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): bad_trait = "omvs:bad_trait" user_admin = UserAdmin(