diff --git a/.github/workflows/.github-actions.yml b/.github/workflows/.github-actions.yml index b2cd022f..bb2e2be2 100644 --- a/.github/workflows/.github-actions.yml +++ b/.github/workflows/.github-actions.yml @@ -2,23 +2,28 @@ name: pyRACF Linting & Unit Test on: [push, pull_request] jobs: build: + strategy: + fail-fast: false + matrix: + 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: '3.11' - - 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 + python-version: ${{ matrix.python-version }} + - 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: flake8 . + run: poetry run flake8 . - name: Pylint - run: pylint --recursive=y . + run: poetry run pylint --recursive=y . - name: Unit Test - run: coverage run tests/test_runner.py + run: poetry run coverage run tests/test_runner.py - name: Code Coverage - run: coverage report -m + run: poetry run coverage report -m 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/.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 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 3fe01bf7..85387d5e 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) } } } @@ -94,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"] ) } } @@ -119,6 +125,7 @@ pipeline { always { echo "Cleaning up workspace..." cleanWs() + clean_python_environment() } } } @@ -145,26 +152,39 @@ 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" ] } 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 """ - ${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 + rm -rf ~/.cache + rm -rf ~/.local + """ +} + +def install_poetry(python) { + echo "Installing Poetry..." + + sh "bash -c 'curl -sSL https://install.python-poetry.org | ${python} -'" +} + +def build_poetry_environment(python) { + echo "Building Poetry environment for '${python}'..." + + sh """ + poetry env use ${python} + poetry install --no-root + poetry env info """ } @@ -172,12 +192,12 @@ 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 info + poetry run flake8 . + poetry run pylint --recursive=y . + poetry run coverage run tests/test_runner.py + poetry run coverage report -m """ } @@ -185,10 +205,11 @@ 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 -fdx + poetry env use ${python} + poetry env info + poetry build + ${python} -m pip install dist/${wheel} cd tests/function_test ${python} function_test.py """ @@ -212,6 +233,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,47 +283,82 @@ def publish( ) ).trim() + 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]["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}'..." sh """ - git clean -f -d -e 'venv_*' - . venv_${python}/bin/activate - ${python} -m pip wheel . + git clean -fdx + 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..." - 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 \"@${wheel_default}\"" + upload_asset(release_id, wheel_publish) + if (tar_published == false) { + 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..." + + sh ( + 'poetry publish \\' + + '--repository=test \\' + + '--username=${pypi_username} \\' + + '--password=${pypi_password}' ) } } } +def upload_asset(release_id, release_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=${release_asset}\" " + + "--data-binary \"@dist/${release_asset}\"" + ) +} + 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 python_executable = python def python_label = python.replace("python", "Python ") description += ( - "Install for ${python_label}:\\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.keySet()[-1] + 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" + ) + return description } diff --git a/README.md b/README.md index 637d5a3c..dbfce06b 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/build_extension.py b/build_extension.py new file mode 100644 index 00000000..95046322 --- /dev/null +++ b/build_extension.py @@ -0,0 +1,34 @@ +"""Build IRRSMO00 (cpyracf) 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..c702c629 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,21 +1,27 @@ [build-system] - build-backend = "setuptools.build_meta" - requires = ["setuptools>=61"] + build-backend = "poetry.core.masonry.api" + requires = ["poetry-core>=1.7.0", "setuptools>=61"] -[project] +[tool.poetry] name="pyracf" - version="1.0a2" + version="1.0b1" description="Python interface to RACF using IRRSMO00 RACF Callable Service." + license = "Apache-2.0" 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 ", + ] + maintainers = [ + "Leonard J. Carcaramo Jr ", + "Elijah Swift ", ] readme = "README.md" - requires-python = ">=3.10" + 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", @@ -28,24 +34,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.9.1" + flake8 = ">=6.1.0" + pylint = ">=3.0.0" + coverage = ">=7.3.2" + wheel = ">=0.41.2" [tool.isort] profile = "black" @@ -54,7 +59,6 @@ max-args = 6 max-returns = 7 max-attributes = 10 - ignore-patterns = "venv_*" [tool.pylint.'MESSAGES CONTROL'] disable = """ diff --git a/pyracf/__init__.py b/pyracf/__init__.py index 70dd53f6..9254e04e 100644 --- a/pyracf/__init__.py +++ b/pyracf/__init__.py @@ -1,6 +1,10 @@ """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.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/access/access_admin.py b/pyracf/access/access_admin.py index 85d9e64d..46a13e4e 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.""" @@ -21,24 +22,23 @@ 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:id": "authid", - "base:profile": "racf:profile", + "base:model_profile_class": "racf:fclass", + "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: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__( @@ -53,23 +53,7 @@ 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( + def permit( self, resource: str, class_name: str, @@ -78,9 +62,9 @@ def alter( volume: Union[str, None] = None, generic: bool = False, ) -> Union[dict, bytes]: - """Alter an existing permission.""" - traits["base:id"] = auth_id - self._build_segment_dictionaries(traits) + """Create or change a permission""" + traits["base:auth_id"] = auth_id + 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 @@ -96,8 +80,8 @@ def delete( generic: bool = False, ) -> Union[dict, bytes]: """Delete a permission.""" - traits = {"base:id": auth_id} - self._build_segment_dictionaries(traits) + traits = {"base:auth_id": auth_id} + 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/add_operation_error.py b/pyracf/common/add_operation_error.py new file mode 100644 index 00000000..855c6247 --- /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 cannot be added because it already exists. + """ + + def __init__(self, profile_name: str, class_name: str) -> None: + self.message = "Refusing to make security request to IRRSMO00." + 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/alter_operation_error.py b/pyracf/common/alter_operation_error.py new file mode 100644 index 00000000..fbec601f --- /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 cannot be altered because it does not exist. + """ + + def __init__(self, profile_name: str, class_name: str) -> None: + self.message = "Refusing to make security request to IRRSMO00." + 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.c b/pyracf/common/irrsmo00.c index 3845e412..8ebdc8d4 100644 --- a/pyracf/common/irrsmo00.c +++ b/pyracf/common/irrsmo00.c @@ -13,6 +13,23 @@ typedef struct { char str[8]; } VarStr_T; +// This function changes any null character not preceded by '>' to a blank character. +// 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) { + for (int i = 1; i < str_len; i++){ + if (str[i] == 0) { + if (str[i-1] == 0x6E) { + return; + } + else { + str[i] = 0x40; + } + } + } +} + static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) { const unsigned int xml_len; const unsigned int input_opts; @@ -30,7 +47,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,6 +72,7 @@ static PyObject* call_irrsmo00(PyObject* self, PyObject* args, PyObject *kwargs) rsp ); + null_byte_fix(rsp,rsp_len); return Py_BuildValue("y", rsp); } 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/common/logger.py b/pyracf/common/logger.py index ed1f3dc8..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" str: diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index c9540769..00736756 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -10,12 +10,16 @@ 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: """Base Class for RACF Administration Interface.""" _valid_segment_traits = {} + _extracted_key_value_pair_segment_traits_map = {} + _case_sensitive_extracted_values = [] __logger = Logger() def __init__( @@ -62,13 +66,13 @@ 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 = {} 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: @@ -121,7 +125,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: @@ -153,7 +157,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, @@ -200,7 +204,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: @@ -256,19 +260,37 @@ 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_segment_dictionary(self, segments: List[str]) -> None: """Build segment dictionaries for profile extract.""" + bad_segments = [] for segment in segments: if segment in self._valid_segment_traits: - self._segment_traits[segment] = segments[segment] + self._segment_traits[segment] = True + 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 - 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: + 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: + bad_traits.append(trait) + if bad_traits: + self.__clear_state(SecurityRequest) + raise SegmentTraitError(bad_traits, self._profile_type) + # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits @@ -300,22 +322,29 @@ 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"][ + return result["securityResult"][self._profile_type]["commands"][0]["profiles"][ index ] 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. + 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 @@ -344,15 +373,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 ) @@ -393,11 +422,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 +463,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 +473,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 +502,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 +547,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 +571,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 +580,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 +609,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 +617,7 @@ def __format_semi_tabular_data( def __add_key_value_pairs_to_segment( self, + segment_name: str, segment: dict, message: str, ) -> None: @@ -583,22 +627,30 @@ 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] = [] values = [ - self._cast_from_str(value) + str(self._cast_from_str(value)) for value in value.split() if value != "NONE" ] segment[current_key] += values else: - segment[current_key] = self._cast_from_str(value) + case_sensitive = False + if current_key in self._case_sensitive_extracted_values: + case_sensitive = True + segment[current_key] = self._cast_from_str( + value, case_sensitive=case_sensitive + ) key = "".join(sub_tokens[1:]) if len(sub_tokens) == 1: if i < len(tokens) - 1 and " " in sub_tokens[0] and i != 0: @@ -612,7 +664,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] ) @@ -649,10 +703,15 @@ def _clean_and_separate(self, value: str) -> 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 value in ("n/a", "none", "none specified", "no", "None"): + if not case_sensitive: + value = value.lower() + if value in ("n/a", "none", "none specified", "no", "None", "unknown"): return None if value in ( "in effect", @@ -682,25 +741,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: @@ -712,8 +776,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/common/security_request_error.py b/pyracf/common/security_request_error.py index d197a48b..6a20bbeb 100644 --- a/pyracf/common/security_request_error.py +++ b/pyracf/common/security_request_error.py @@ -17,3 +17,17 @@ def __init__(self, result: dict) -> None: def __str__(self) -> str: return self.message + + 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_message_id in "".join(messages): + return True + else: + return False 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/pyracf/common/segment_error.py b/pyracf/common/segment_error.py new file mode 100644 index 00000000..33d6f667 --- /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, bad_segments: list, profile_type: str) -> None: + self.message = "Unable to build Security Request.\n\n" + for segment in bad_segments: + self.message += ( + f"'{segment}' is not a known 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..64f46fda --- /dev/null +++ b/pyracf/common/segment_trait_error.py @@ -0,0 +1,18 @@ +"""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 a bad segment-trait combination in the traits dictionary. + """ + + 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 " + + f"combination for '{profile_type}'.\n" + ) + + def __str__(self) -> str: + return self.message diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index d175dbda..2527118e 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): @@ -19,22 +20,17 @@ 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:universal_access": "racf:uacc", } } super().__init__( @@ -53,14 +49,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) # ============================================================================ @@ -70,14 +66,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) # ============================================================================ @@ -87,50 +83,45 @@ 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) # ============================================================================ # 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. """ - 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( + def take_away_group_access_attribute( self, userid: str, group: str ) -> Union[dict, bytes]: """ 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 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) + def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: + """Create or change a group connection.""" + 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 d711dca0..1995e5af 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -2,7 +2,10 @@ 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 from .data_set_request import DataSetRequest @@ -20,45 +23,41 @@ 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: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__( @@ -100,12 +99,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) + if self._generate_requests_only: + 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) + try: + 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_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 +131,20 @@ def alter( generic: bool = False, ) -> Union[dict, bytes]: """Alter an existing data set profile.""" - self._build_segment_dictionaries(traits) + if self._generate_requests_only: + 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) + try: + 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(): + raise AlterOperationError(data_set, self._profile_type) + 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) @@ -126,13 +152,13 @@ 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, ) -> 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 60253c98..63b22f7b 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -2,7 +2,10 @@ 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 from .group_request import GroupRequest @@ -20,26 +23,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", }, @@ -98,7 +96,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]: @@ -111,7 +109,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]: @@ -124,23 +122,43 @@ 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_trait_dictionary(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.contains_error_message(self._profile_type, "ICH51003I"): + raise exception + self._build_segment_trait_dictionary(traits) + group_request = GroupRequest(group, "set") + self._build_xml_segments(group_request) + return self._make_request(group_request) + raise AddOperationError(group, self._profile_type) + + def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" - self._build_segment_dictionaries(traits) + if self._generate_requests_only: + 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) + try: + self.extract(group) + except SecurityRequestError: + raise AlterOperationError(group, self._profile_type) + 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) 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) + 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 bae65a7b..f42108d1 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -2,7 +2,10 @@ 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 from .resource_request import ResourceRequest @@ -20,154 +23,155 @@ 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: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: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:case_allowed": "case", + "cdtinfo:default_racroute_return_code": "defaultrc", + "cdtinfo:valid_first_characters": "first", + "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", + "cdtinfo:max_length": "maxlenx", + "cdtinfo:max_length_entityx": "maxlength", + "cdtinfo:member_class_name": "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:custom_field_data_type": "type", + "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": "mxlength", + "cfdef:max_numeric_value": "maxvalue", + "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_algorithms": "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_identity_map": "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_name": "racf:parmname", + "svfmr:script_name": "racf:script", }, - "svfmr": {"svfmr:parmname": "racf:parmname", "svfmr:script": "racf:script"}, "tme": { "tme:children": "racf:children", "tme:groups": "racf:groups", @@ -176,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": "genericProfileChecking", + "genlist": "genericProfileSharing", + "group": "groupingClassName", + "keyqualifiers": "keyQualifiers", + "macprocessing": "manditoryAccessControlProcessing", + "maxlenx": "maxLength", + "maxlength": "maxLengthEntityx", + "member": "memberClassName", + "operations": "operations", + "other": "validOtherCharacters", + "posit": "positNumber", + "profilesallowed": "profilesAllowed", + "raclist": "raclistAllowed", + "signal": "sendEnfSignalOnProfileCreation", + "seclabelsrequired": "securityLabelsRequired", + "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, @@ -212,6 +270,215 @@ 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"], + profile_only=True, + ) + 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"], + profile_only=True, + ) + 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"], + profile_only=True, + ) + 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"], + profile_only=True, + ) + 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 "sigver:library" in traits: + 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 "sigver:library" in traits: + 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_only=True, + ) + 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"], + profile_only=True, + ) + 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 # ============================================================================ @@ -219,25 +486,50 @@ def add( self, resource: str, class_name: str, traits: dict = {} ) -> Union[dict, bytes]: """Create a new general resource profile.""" - self._build_segment_dictionaries(traits) + if self._generate_requests_only: + 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) + try: + 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_trait_dictionary(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]: + def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, bytes]: """Alter an existing general resource profile.""" - self._build_segment_dictionaries(traits) + if self._generate_requests_only: + 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) + try: + 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_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) 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) + 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 5f47b071..0b3230ab 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:generic_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_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", + "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__( @@ -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[str, List[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) # ============================================================================ @@ -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 @@ -145,137 +145,167 @@ def get_class_attributes(self, class_name: str) -> Union[list, bytes]: ] # ============================================================================ - # Audit Class + # Audit Classes # ============================================================================ - 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[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_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[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}) return self._to_steps(result) # ============================================================================ - # Active Class + # Active Classes # ============================================================================ - def add_active_class(self, class_name: str) -> Union[dict, bytes]: + def add_active_classes( + self, class_names: Union[str, List[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_classes": 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[str, List[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_classes": class_names}) return self._to_steps(result) # ============================================================================ - # Statistics Class + # Statistics Classes # ============================================================================ - 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[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_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[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}) return self._to_steps(result) # ============================================================================ - # Generic Command Processing Class + # Generic Command Processing Classes # ============================================================================ - def add_generic_command_processing_class( - self, class_name: str + def add_generic_command_processing_classes( + self, class_names: Union[str, List[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:generic_command_classes": 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[str, List[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:generic_command_classes": class_names} + ) return self._to_steps(result) # ============================================================================ - # Generic Profile Checking Class + # Generic Profile Checking Classes # ============================================================================ - 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[str, List[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_classes": 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[str, List[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_classes": class_names} ) return self._to_steps(result) # ============================================================================ - # Generic Profile Sharing Class + # Generic Profile Sharing Classes # ============================================================================ - def add_generic_profile_sharing_class(self, class_name: str) -> Union[dict, bytes]: + def add_generic_profile_sharing_classes( + self, class_names: Union[str, List[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_classes": 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[str, List[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_classes": class_names} ) return self._to_steps(result) # ============================================================================ - # Global Access Class + # Global Access Classes # ============================================================================ - 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[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_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[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}) return self._to_steps(result) # ============================================================================ - # Raclist Class + # Raclist Classes # ============================================================================ - 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[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_class(self, class_name: str) -> Union[dict, bytes]: + def remove_raclist_classes( + self, class_names: Union[str, List[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) # ============================================================================ @@ -283,7 +313,7 @@ def remove_raclist_class(self, class_name: str) -> Union[dict, bytes]: # ============================================================================ 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) @@ -293,9 +323,11 @@ 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) + self._add_traits_directly_to_request_xml_with_no_segments( + setropts_request, alter=True + ) return self._make_request(setropts_request) # ============================================================================ @@ -506,12 +538,12 @@ 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 elif key_raw in class_list_fields: - self.__add_class_list(profile, key, value_raw) + self.__add_classes_list(profile, key, value_raw) continue elif key_raw in generic_list_fields: value = self.__to_list(value_raw) @@ -578,7 +610,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]: @@ -591,8 +623,8 @@ def __to_list(self, value_raw: str, n: int = 1) -> List[str]: for i in range(0, len(tokens), n) ] - def __add_class_list(self, profile: dict, class_key: str, value_raw: str) -> None: - """Add a class list to profile""" + def __add_classes_list(self, profile: dict, class_key: str, value_raw: str) -> None: + """Add a class list to profile.""" if "classes" not in profile: profile["classes"] = {} class_key = class_key.replace("Classes", "") @@ -685,7 +717,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 +729,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..beba75cd 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -2,7 +2,10 @@ 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 from .user_request import UserRequest @@ -20,196 +23,188 @@ 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:resume": "resumedate", - "base:revoke": "revokedate", - "base:revokefl": "racf:revokefl", - "base:roaudit": "racf:roaudit", - "base:seclabel": "seclabel", - "base:seclevel": "racf:seclevel", + "base:restrict_global_access_checking": "racf:rest", + "base:resume_date": "resumedate", + "base:revoke_date": "revokedate", + "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_non_shared_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:default_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", + "memlimit": "maxNonSharedMemory", + "shmemmax": "maxSharedMemory", + }, + "tso": { + "acctnum": "accountNumber", + "holdclass": "holdClass", + "jobclass": "jobClass", + "msgclass": "messageClass", + "proc": "logonProcedure", + "size": "defaultRegionSize", + "maxsize": "maxRegionSize", + "sysoutclass": "sysoutClass", + "unit": "dataSetAllocationUnit", + "userdata": "userData", + "command": "logonCommand", + }, + } + self._case_sensitive_extracted_values = ["homeDirectory", "defaultShell"] super().__init__( "user", debug=debug, @@ -282,7 +277,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}) @@ -294,7 +289,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}) @@ -316,14 +311,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} ) @@ -332,64 +327,440 @@ 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 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: 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) + + # ============================================================================ + # 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: 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) + + # ============================================================================ + # 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, None, 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 # ============================================================================ 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: 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"], 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"], 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"], 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"], 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"], 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"], 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"], 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) + # ============================================================================ - def get_omvs_home(self, userid: str) -> Union[str, None, bytes]: + # 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"], 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", "home") + profile = self.extract(userid, segments=["omvs"], profile_only=True) + return self._get_field(profile, "omvs", "homeDirectory", string=True) - def set_omvs_home( + 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": home_directory}) + result = self.alter(userid, traits={"omvs:home_directory": home_directory}) + return self._to_steps(result) + + # ============================================================================ + # OMVS Default Shell + # ============================================================================ + 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"], profile_only=True) + return self._get_field(profile, "omvs", "defaultShell", string=True) + + def set_omvs_default_shell( + self, + userid: str, + default_shell: Union[str, bool], + ) -> Union[dict, bytes]: + """Set a user's OMVS default shell.""" + result = self.alter(userid, traits={"omvs:default_shell": default_shell}) + 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"], 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"], 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"], 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"], 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"], 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"], 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 Default Region Size + # ============================================================================ + 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"], profile_only=True) + return self._get_field(profile, "tso", "defaultRegionSize") + + def set_tso_default_region_size( + self, + userid: str, + default_region_size: Union[int, bool], + ) -> Union[dict, bytes]: + """Set a user's TSO default region size.""" + result = self.alter( + userid, traits={"tso:default_region_size": default_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"], 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"], 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) # ============================================================================ - # OMVS Program + # TSO Data Set Allocation Unit # ============================================================================ - def get_omvs_program(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") + 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"], profile_only=True) + return self._get_field(profile, "tso", "dataSetAllocationUnit", string=True) - def set_omvs_program( + def set_tso_data_set_allocation_unit( self, userid: str, - program: str, + data_set_allocation_unit: Union[str, bool], ) -> Union[dict, bytes]: - """Set a user's OMVS program.""" - result = self.alter(userid, traits={"omvs:program": program}) + """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) # ============================================================================ @@ -397,23 +768,43 @@ 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) - - def alter(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: + if self._generate_requests_only: + self._build_segment_trait_dictionary(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.contains_error_message(self._profile_type, "ICH30001I"): + raise exception + self._build_segment_trait_dictionary(traits) + user_request = UserRequest(userid, "set") + self._build_xml_segments(user_request) + return self._make_request(user_request) + raise AddOperationError(userid, self._profile_type) + + def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: """Alter an existing user.""" - self._build_segment_dictionaries(traits) + if self._generate_requests_only: + 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) + try: + self.extract(userid) + except SecurityRequestError: + raise AlterOperationError(userid, self._profile_type) + 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) 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) + 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) 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() diff --git a/tests/access/access_log_samples/add_access_error.log b/tests/access/access_log_samples/permit_access_error.log similarity index 78% rename from tests/access/access_log_samples/add_access_error.log rename to tests/access/access_log_samples/permit_access_error.log index bf555c0a..28151cbf 100644 --- a/tests/access/access_log_samples/add_access_error.log +++ b/tests/access/access_log_samples/permit_access_error.log @@ -1,17 +1,17 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.add() + AccessAdmin.permit() { "base": { "base:access": { - "value": "READ", + "value": "ALTER", "operation": null }, - "base:id": { - "value": "ESWIFT", + "base:auth_id": { + "value": "MCGINLEY", "operation": null } } @@ -20,20 +20,20 @@ [pyRACF:Debug] Request XML - AccessAdmin.add() + AccessAdmin.permit() - READ - ESWIFT + ALTER + MCGINLEY [pyRACF:Debug] Result XML - AccessAdmin.add() + AccessAdmin.permit() @@ -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.permit() { @@ -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/permit_access_success.log similarity index 78% rename from tests/access/access_log_samples/add_access_success.log rename to tests/access/access_log_samples/permit_access_success.log index 9b281917..d82660a9 100644 --- a/tests/access/access_log_samples/add_access_success.log +++ b/tests/access/access_log_samples/permit_access_success.log @@ -1,16 +1,16 @@ [pyRACF:Debug] Request Dictionary - AccessAdmin.add() + AccessAdmin.permit() { "base": { "base:access": { - "value": "READ", + "value": "NONE", "operation": null }, - "base:id": { + "base:auth_id": { "value": "ESWIFT", "operation": null } @@ -20,20 +20,20 @@ [pyRACF:Debug] Request XML - AccessAdmin.add() + AccessAdmin.permit() - READ - ESWIFT + NONE + ESWIFT [pyRACF:Debug] Result XML - AccessAdmin.add() + AccessAdmin.permit() @@ -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.permit() { @@ -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/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/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/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 4c07d80e..d21117d0 100644 --- a/tests/access/test_access_constants.py +++ b/tests/access/test_access_constants.py @@ -15,19 +15,15 @@ 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( - "alter_access_result_success.json" +# 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" +) +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 @@ -44,11 +40,8 @@ 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") +# Permit Access +TEST_PERMIT_ACCESS_REQUEST_XML = get_sample("permit_access_request.xml") # Delete Access TEST_DELETE_ACCESS_REQUEST_XML = get_sample("delete_access_request.xml") @@ -57,5 +50,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_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 2a34cc13..8f70e86b 100644 --- a/tests/access/test_access_debug_logging.py +++ b/tests/access/test_access_debug_logging.py @@ -24,37 +24,39 @@ class TestAccessDebugLogging(unittest.TestCase): ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") # ============================================================================ - # Add Access + # Permit Access # ============================================================================ - def test_add_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_ADD_ACCESS_RESULT_SUCCESS_XML + TestAccessConstants.TEST_PERMIT_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.permit( + "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_PERMIT_ACCESS_SUCCESS_LOG + ) - def test_add_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_ADD_ACCESS_RESULT_ERROR_XML + TestAccessConstants.TEST_PERMIT_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.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_ADD_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 d6473ee7..4fbe20bc 100644 --- a/tests/access/test_access_request_builder.py +++ b/tests/access/test_access_request_builder.py @@ -18,17 +18,11 @@ 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( + 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 2572ac0e..b8d15926 100644 --- a/tests/access/test_access_result_parser.py +++ b/tests/access/test_access_result_parser.py @@ -20,71 +20,37 @@ class TestAccessResultParser(unittest.TestCase): access_admin = AccessAdmin() # ============================================================================ - # Add Access + # Permit Access # ============================================================================ - def test_access_admin_can_parse_add_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_ADD_ACCESS_RESULT_SUCCESS_XML + TestAccessConstants.TEST_PERMIT_ACCESS_RESULT_SUCCESS_XML ) self.assertEqual( - self.access_admin.add( - "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "READ"} + self.access_admin.permit( + "TESTING", "ELIJTEST", "ESWIFT", traits={"base:access": "NONE"} ), - 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 - # ============================================================================ - def test_access_admin_can_parse_alter_access_success_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestAccessConstants.TEST_ALTER_ACCESS_RESULT_SUCCESS_XML - ) - self.assertEqual( - self.access_admin.alter( - "TESTING", "ELITEST", "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( - "TESTING", "ELITEST", "MCGINLEY", traits={"base:access": "NONE"} + 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/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/connection/connection_log_samples/add_connection_error.log b/tests/connection/connection_log_samples/connect_connection_error.log similarity index 78% rename from tests/connection/connection_log_samples/add_connection_error.log rename to tests/connection/connection_log_samples/connect_connection_error.log index c33b1402..c7473430 100644 --- a/tests/connection/connection_log_samples/add_connection_error.log +++ b/tests/connection/connection_log_samples/connect_connection_error.log @@ -1,25 +1,39 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.add() + ConnectionAdmin.connect() -{} +{ + "base": { + "base:operations": { + "value": false, + "operation": "delete" + }, + "base:special": { + "value": true, + "operation": null + } + } +} [pyRACF:Debug] Request XML - ConnectionAdmin.add() + ConnectionAdmin.connect() - + + + + [pyRACF:Debug] Result XML - ConnectionAdmin.add() + ConnectionAdmin.connect() @@ -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.connect() { @@ -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/connect_connection_success.log similarity index 76% rename from tests/connection/connection_log_samples/add_connection_success.log rename to tests/connection/connection_log_samples/connect_connection_success.log index 5de10c4e..f7782fa8 100644 --- a/tests/connection/connection_log_samples/add_connection_success.log +++ b/tests/connection/connection_log_samples/connect_connection_success.log @@ -1,25 +1,39 @@ [pyRACF:Debug] Request Dictionary - ConnectionAdmin.add() + ConnectionAdmin.connect() -{} +{ + "base": { + "base:operations": { + "value": false, + "operation": "delete" + }, + "base:special": { + "value": true, + "operation": null + } + } +} [pyRACF:Debug] Request XML - ConnectionAdmin.add() + ConnectionAdmin.connect() - + + + + [pyRACF:Debug] Result XML - ConnectionAdmin.add() + ConnectionAdmin.connect() @@ -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.connect() { @@ -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/alter_connection_request.xml b/tests/connection/connection_request_samples/connect_connection_request.xml similarity index 89% rename from tests/connection/connection_request_samples/alter_connection_request.xml rename to tests/connection/connection_request_samples/connect_connection_request.xml index b39b16c9..f6c274d1 100644 --- a/tests/connection/connection_request_samples/alter_connection_request.xml +++ b/tests/connection/connection_request_samples/connect_connection_request.xml @@ -1,5 +1,6 @@ + \ 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_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/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_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/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 b1cd686c..ca1910af 100644 --- a/tests/connection/test_connection_constants.py +++ b/tests/connection/test_connection_constants.py @@ -15,26 +15,18 @@ 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" +# Connect Connection +TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML = get_sample( + "connect_connection_result_success.xml" ) -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" +TEST_CONNECT_CONNECTION_RESULT_SUCCESS_DICTIONARY = get_sample( + "connect_connection_result_success.json" ) - -# Alter Connection -TEST_ALTER_CONNECTION_RESULT_SUCCESS_XML = get_sample( - "alter_connection_result_success.xml" -) -TEST_ALTER_CONNECTION_RESULT_SUCCESS_DICTIONARY = get_sample( - "alter_connection_result_success.json" +TEST_CONNECT_CONNECTION_RESULT_ERROR_XML = get_sample( + "connect_connection_result_error.xml" ) -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_DICTIONARY = get_sample( + "connect_connection_result_error.json" ) @@ -56,13 +48,10 @@ 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 = { - "base:operator": False, +# Connect Connection +TEST_CONNECT_CONNECTION_REQUEST_XML = get_sample("connect_connection_request.xml") +TEST_CONNECT_CONNECTION_REQUEST_TRAITS = { + "base:operations": False, "base:special": True, } @@ -92,15 +81,15 @@ 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" ) # ============================================================================ # 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_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 a2cdf963..7adabd20 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 + # Connect Connection # ============================================================================ - def test_add_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_ADD_CONNECTION_RESULT_SUCCESS_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_SUCCESS_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): - self.connection_admin.add("ESWIFT", "TESTGRP0") + self.connection_admin.connect( + "ESWIFT", + "TESTGRP0", + traits=TestConnectionConstants.TEST_CONNECT_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_CONNECT_CONNECTION_SUCCESS_LOG ) - def test_add_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_ADD_CONNECTION_RESULT_ERROR_XML + TestConnectionConstants.TEST_CONNECT_CONNECTION_RESULT_ERROR_XML ) stdout = io.StringIO() with contextlib.redirect_stdout(stdout): try: - self.connection_admin.add("ESWIFT", "TESTGRP0") + self.connection_admin.connect( + "ESWIFT", + "TESTGRP0", + traits=TestConnectionConstants.TEST_CONNECT_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_CONNECT_CONNECTION_ERROR_LOG ) diff --git a/tests/connection/test_connection_request_builder.py b/tests/connection/test_connection_request_builder.py index e1859bba..3667acd1 100644 --- a/tests/connection/test_connection_request_builder.py +++ b/tests/connection/test_connection_request_builder.py @@ -18,20 +18,14 @@ 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( + 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 1a1f7653..dcd724a2 100644 --- a/tests/connection/test_connection_result_parser.py +++ b/tests/connection/test_connection_result_parser.py @@ -20,71 +20,41 @@ class TestConnectionResultParser(unittest.TestCase): connection_admin = ConnectionAdmin() # ============================================================================ - # Add Connection + # Connect Connection # ============================================================================ - def test_connection_admin_can_parse_add_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_ADD_CONNECTION_RESULT_SUCCESS_XML + TestConnectionConstants.TEST_CONNECT_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 - # ============================================================================ - def test_connection_admin_can_parse_alter_connection_success_xml( - self, - call_racf_mock: Mock, - ): - call_racf_mock.return_value = ( - TestConnectionConstants.TEST_ALTER_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/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( 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_bad_attribute_error.json b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.json new file mode 100644 index 00000000..b5d84c93 --- /dev/null +++ b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_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_bad_attribute_error.xml b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_attribute_error.xml new file mode 100644 index 00000000..3a0a02de --- /dev/null +++ b/tests/data_set/data_set_result_samples/extract_data_set_result_bad_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/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/test_data_set_constants.py b/tests/data_set/test_data_set_constants.py index b4801ded..cf050ab2 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_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( + "extract_data_set_result_bad_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 924e5fdf..c4417d35 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 DataSetAdmin, SecurityRequestError +from pyracf import ( + AddOperationError, + AlterOperationError, + DataSetAdmin, + SecurityRequestError, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -26,9 +31,48 @@ 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", + traits=TestDataSetConstants.TEST_ADD_DATA_SET_REQUEST_TRAITS, + ), + TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_SUCCESS_DICTIONARY, + ) + + def test_data_set_admin_thows_error_on_add_existing_data_set_profile( + self, + call_racf_mock: Mock, + ): + profile_name = "ESWIFT.TEST.T1136242.P3020470" + 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, + "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.", ) + + 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", @@ -37,22 +81,23 @@ 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 + # 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.return_value = ( - TestDataSetConstants.TEST_ADD_DATA_SET_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BAD_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_BAD_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ @@ -62,9 +107,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_ONLY_SUCCESS_XML, + TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_XML, + ] self.assertEqual( self.data_set_admin.alter( "ESWIFT.TEST.T1136242.P3020470", @@ -73,14 +119,59 @@ 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" + call_racf_mock.side_effect = [ + TestDataSetConstants.TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_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, + "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.", + ) + + 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, 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_ONLY_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", @@ -94,43 +185,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_bad_attribute_error.json b/tests/group/group_result_samples/extract_group_result_bad_attribute_error.json new file mode 100644 index 00000000..1ef0740a --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_bad_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_bad_attribute_error.xml b/tests/group/group_result_samples/extract_group_result_bad_attribute_error.xml new file mode 100644 index 00000000..ba6b7c61 --- /dev/null +++ b/tests/group/group_result_samples/extract_group_result_bad_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/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/connection/connection_result_samples/add_connection_result_error.xml b/tests/group/group_result_samples/extract_group_result_base_only_error.xml similarity index 57% rename from tests/connection/connection_result_samples/add_connection_result_error.xml rename to tests/group/group_result_samples/extract_group_result_base_only_error.xml index 07f9fe66..9cef8fac 100644 --- a/tests/connection/connection_result_samples/add_connection_result_error.xml +++ b/tests/group/group_result_samples/extract_group_result_base_only_error.xml @@ -1,15 +1,14 @@ - + 8 16 - 8 - CONNECT ESWIFT GROUP (TESTGRP0) + 4 + LISTGRP 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/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..a971c3be 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -42,11 +42,23 @@ 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" +) +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_BAD_ATTRIBUTE_ERROR_XML = get_sample( + "extract_group_result_bad_attribute_error.xml" +) +TEST_EXTRACT_GROUP_RESULT_BAD_ATTRIBUTE_ERROR_DICTIONARY = get_sample( + "extract_group_result_bad_attribute_error.json" ) # Delete Group @@ -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 f0ddacd7..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 @@ -69,7 +74,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 +90,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_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_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 8a2f63cb..b02441da 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 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,42 @@ 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" + 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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{group_name}' already exists as a '{self.group_admin._profile_type}' profile.", + ) + + # 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.return_value = TestGroupConstants.TEST_ADD_GROUP_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BAD_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_BAD_ATTRIBUTE_ERROR_DICTIONARY, ) # ============================================================================ @@ -58,9 +87,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_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_XML, + ] self.assertEqual( self.group_admin.alter( "TESTGRP0", traits=TestGroupConstants.TEST_ALTER_GROUP_REQUEST_TRAITS @@ -68,14 +98,35 @@ def test_group_admin_can_parse_alter_group_success_xml( TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_DICTIONARY, ) - # Error: invalid gid "3000000000" - def test_group_admin_can_parse_alter_group_error_xml( + def test_group_admin_throws_error_on_alter_new_group( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML + group_name = "TESTGRP0" + 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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{group_name}' does not exist as a '{self.group_admin._profile_type}' profile.", ) + + # Error: bad gid "3000000000" + def test_group_admin_can_parse_alter_group_error_xml( + self, + call_racf_mock: Mock, + ): + call_racf_mock.side_effect = [ + TestGroupConstants.TEST_EXTRACT_GROUP_RESULT_BASE_ONLY_SUCCESS_XML, + TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_XML, + ] with self.assertRaises(SecurityRequestError) as exception: self.group_admin.alter( "TESTGRP0", @@ -97,20 +148,20 @@ 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, ) - 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 @@ -122,7 +173,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/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_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/connection/connection_request_samples/add_connection_request.xml b/tests/resource/resource_request_samples/add_kerberos_realm_request.xml similarity index 56% rename from tests/connection/connection_request_samples/add_connection_request.xml rename to tests/resource/resource_request_samples/add_kerberos_realm_request.xml index 4860ba29..5ae3d3aa 100644 --- a/tests/connection/connection_request_samples/add_connection_request.xml +++ b/tests/resource/resource_request_samples/add_kerberos_realm_request.xml @@ -1,3 +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_bad_class_error.json b/tests/resource/resource_result_samples/extract_resource_result_bad_class_error.json new file mode 100644 index 00000000..dde77d51 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_bad_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_bad_class_error.xml b/tests/resource/resource_result_samples/extract_resource_result_bad_class_error.xml new file mode 100644 index 00000000..6851ec10 --- /dev/null +++ b/tests/resource/resource_result_samples/extract_resource_result_bad_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/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 15538f05..b23c189e 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -52,6 +52,15 @@ 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( + "extract_resource_result_bad_class_error.xml" +) +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( @@ -107,8 +116,192 @@ 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") + +# ============================================================================ +# 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", + "genericProfileSharing": "disallowed", + "genericProfileChecking": "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_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 0fa402a3..525366ee 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 ResourceAdmin, SecurityRequestError +from pyracf import ( + AddOperationError, + AlterOperationError, + ResourceAdmin, + SecurityRequestError, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -26,27 +31,65 @@ 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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget 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: 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.return_value = ( - TestResourceConstants.TEST_ADD_RESOURCE_RESULT_ERROR_XML - ) + call_racf_mock.side_effect = [ + 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_ADD_RESOURCE_RESULT_ERROR_DICTIONARY, + TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BAD_CLASS_ERROR_DICTIONARY, ) # ============================================================================ @@ -56,9 +99,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", @@ -68,14 +112,61 @@ def test_resource_admin_can_parse_alter_resource_success_xml( TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_DICTIONARY, ) - # Error: Invalid Universal Access ALL - def test_resource_admin_can_parse_alter_resource_error_xml( + def test_resource_admin_throws_error_on_alter_new_profile( self, call_racf_mock: Mock, ): - call_racf_mock.return_value = ( - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_XML + 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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget 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, + call_racf_mock: Mock, + ): + 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/resource/test_resource_subfunction_extracts.py b/tests/resource/test_resource_subfunction_extracts.py new file mode 100644 index 00000000..2f4787aa --- /dev/null +++ b/tests/resource/test_resource_subfunction_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_subfunction_requests.py b/tests/resource/test_resource_subfunction_requests.py new file mode 100644 index 00000000..e99d80a7 --- /dev/null +++ b/tests/resource/test_resource_subfunction_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/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 new file mode 100644 index 00000000..50c0b32d --- /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_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 new file mode 100644 index 00000000..d6d71cb3 --- /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_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 new file mode 100644 index 00000000..1bf65492 --- /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_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 new file mode 100644 index 00000000..9a077c4d --- /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_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 new file mode 100644 index 00000000..ea221eeb --- /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_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 new file mode 100644 index 00000000..cda59bd3 --- /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_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 new file mode 100644 index 00000000..5bd8d4ac --- /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_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 new file mode 100644 index 00000000..f76ed3d5 --- /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.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 new file mode 100644 index 00000000..eec7ec01 --- /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 a85de899..773c9b08 100644 --- a/tests/setropts/test_setropts_setters.py +++ b/tests/setropts/test_setropts_setters.py @@ -19,118 +19,386 @@ 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_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 ) + 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 + # 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 ) + 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 + # Raclist Refresh # ============================================================================ def test_setropts_admin_build_refresh_raclist_request(self): result = self.setropts_admin.refresh_raclist("elijtest") 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 + ) diff --git a/tests/test_runner.py b/tests/test_runner.py index 4d6b7ede..6253f828 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, @@ -29,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_subfunction_extracts import ( + TestResourceSubfunctionExtracts, +) +from tests.resource.test_resource_subfunction_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 @@ -52,6 +59,7 @@ def __test_suite() -> unittest.TestSuite: TestAccessResultParser, TestAccessRequestBuilder, TestAccessDebugLogging, + TestLogger, TestConnectionResultParser, TestConnectionRequestBuilder, TestConnectionSetters, @@ -66,6 +74,8 @@ def __test_suite() -> unittest.TestSuite: TestResourceGetters, TestResourceSetters, TestResourceDebugLogging, + TestResourceSubfunctionRequests, + TestResourceSubfunctionExtracts, TestGroupResultParser, TestGroupRequestBuilder, TestGroupGetters, diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index 4213b47c..d5d4cb21 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -20,48 +20,57 @@ 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" +) +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" ) - -# 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 +85,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 +103,24 @@ 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( + "extract_user_result_bad_attribute_error.xml" +) +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" +) +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") @@ -103,6 +136,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( @@ -112,33 +148,76 @@ 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", + "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" -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_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_threads": 48, + "omvs:uid": 1919, + "omvs:home_directory": "/u/squidward", + "omvs:default_shell": "/bin/sh", + "tso:account_number": "SB29", + "tso:logon_command": "ISPF", + "tso:hold_class": "A", + "tso:max_region_size": 2048, + "tso:message_class": "B", + "tso:logon_procedure": "PROC", + "tso:default_region_size": 1024, + "tso:sysout_class": "O", + "tso:user_data": "ABCD", + "tso:data_set_allocation_unit": "SYSDA", +} +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") 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, +} +TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED = { + "base:name": "Squidward", + "base:owner": "leonard", + "base:special": True, + "omvs:uid": "2424", + "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" +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( @@ -152,6 +231,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" ) @@ -171,7 +251,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" ) @@ -184,41 +268,167 @@ 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" ) +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_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_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 # ============================================================================ -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( @@ -231,10 +441,14 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # ============================================================================ # Alter User Traits +TEST_ALTER_USER_CSDATA_AND_OMVS_REQUEST_TRAITS = { + "base:special": False, + "omvs:home_directory": "/u/clarinet", + "omvs:default_shell": False, + "csdata:tstcsfld": "testval", +} TEST_ALTER_USER_CSDATA_REQUEST_TRAITS = { "base:special": False, - "omvs:home": "/u/clarinet", - "omvs:program": False, "csdata:tstcsfld": "testval", } diff --git a/tests/user/test_user_debug_logging.py b/tests/user/test_user_debug_logging.py index 615959fa..c3b27d08 100644 --- a/tests/user/test_user_debug_logging.py +++ b/tests/user/test_user_debug_logging.py @@ -27,252 +27,298 @@ 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_SIMPLE + ) + error_traits["omvs:uid"] = 90000000000 + self.user_admin.alter( "squidwrd", - traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE, + 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.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( + # 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, ): 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 + f"({TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR['omvs:uid']})", + error_log, ) # ============================================================================ @@ -287,7 +333,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 +349,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_getters.py b/tests/user/test_user_getters.py index 089a43bf..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,23 +276,264 @@ 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_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_max_file_mapping_pages("squidwrd"), 350 + ) + + def test_user_admin_get_omvs_max_file_mapping_pages_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_file_mapping_pages("squidwrd") + + 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_SUCCESS_XML + ) + self.assertIsNone(self.user_admin.get_omvs_max_file_mapping_pages("squidwrd")) + + # ============================================================================ + # OMVS Max Processes + # ============================================================================ + 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_home_works( + 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_home("squidwrd"), "/u/squidwrd") + self.assertIsNone(self.user_admin.get_omvs_max_shared_memory("squidwrd")) + + 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_home_raises_an_exception_when_extract_fails( + def test_user_admin_get_omvs_max_threads_raises_an_exception_when_extract_fails( self, call_racf_mock: Mock, ): @@ -216,30 +541,32 @@ 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_max_threads("squidwrd") - def test_user_admin_get_omvs_home_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_home("squidwrd")) + self.assertIsNone(self.user_admin.get_omvs_max_threads("squidwrd")) # ============================================================================ - # OMVS Program + # OMVS Home Directory # ============================================================================ - def test_user_admin_get_omvs_program_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_program("squidwrd"), "/bin/sh") + self.assertEqual( + self.user_admin.get_omvs_home_directory("squidwrd"), "/u/squidwrd" + ) - def test_user_admin_get_omvs_program_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, ): @@ -247,13 +574,470 @@ 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_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_program_returns_none_when_no_omvs_segment_exists( + 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_ONLY_NO_OMVS_SUCCESS_XML + 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_program("squidwrd")) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 83381564..7c7a15f5 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 SegmentError, SegmentTraitError, UserAdmin from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -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 @@ -36,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 ) @@ -55,7 +64,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 +74,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 +84,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 @@ -104,9 +113,88 @@ 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, TestUserConstants.TEST_ALTER_USER_REQUEST_UPDATE_SEGMENTS_XML, ) + + # ============================================================================ + # Request Builder Errors + # ============================================================================ + 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(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", + ) + + # 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( + 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( + generate_requests_only=True, + ) + with self.assertRaises(SegmentError) as exception: + user_admin.extract("squidwrd", segments=[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", + ) + + 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 + ) diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py index c3b0ef8e..c7789f98 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 SecurityRequestError, UserAdmin +from pyracf import ( + AddOperationError, + AlterOperationError, + SecurityRequestError, + UserAdmin, +) from pyracf.common.irrsmo00 import IRRSMO00 # Resolves F401 @@ -29,7 +34,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 +46,43 @@ def test_user_admin_can_parse_add_user_success_xml( TestUserConstants.TEST_ADD_USER_RESULT_SUCCESS_DICTIONARY, ) - # Error in environment, SQUIDWRD already added/exists + def test_user_admin_throws_error_on_add_existing_user( + self, + call_racf_mock: Mock, + ): + profile_name = "squidwrd" + 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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{profile_name}' already exists as a '{self.user_admin._profile_type}' profile.", + ) + + # 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.return_value = TestUserConstants.TEST_ADD_USER_RESULT_ERROR_XML + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BAD_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_BAD_ATTRIBUTE_JSON, ) # ============================================================================ @@ -61,9 +92,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_SUCCESS_XML, + TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_XML, + ] self.assertEqual( self.user_admin.alter( "squidwrd", traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS @@ -71,15 +103,39 @@ def test_user_admin_can_parse_alter_user_success_xml( TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_DICTIONARY, ) - # Error: invalid parameter "name" + def test_user_admin_throws_error_on_alter_new_user( + self, + call_racf_mock: Mock, + ): + profile_name = "squidwrd" + call_racf_mock.side_effect = [ + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_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, + "Refusing to make security request to IRRSMO00." + + "\n\nTarget profile " + + f"'{profile_name}' does not exist as a '{self.user_admin._profile_type}' profile.", + ) + + # Error: bad uid '90000000000' 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_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, @@ -97,20 +153,20 @@ 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, ) - 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, + self.user_admin.extract("squidwrd", segments=["omvs"]), + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_JSON, ) # Error in environment, SQUIDWRD already deleted/not added @@ -122,7 +178,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,107 +192,144 @@ 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, ) + 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, + ): + call_racf_mock.return_value = ( + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_XML + ) + self.assertEqual( + self.user_admin.extract("squidwrd", segments=["omvs", "tso"]), + TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY, + ) + # ============================================================================ # 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: bad 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: bad 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) @@ -244,22 +337,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: bad 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) @@ -267,42 +365,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: bad 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) @@ -353,6 +457,56 @@ 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, ) + + # ============================================================================ + # 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, + ) + + # 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, + ): + 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/test_user_setters.py b/tests/user/test_user_setters.py index cdab89a7..5650aaa9 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 # ============================================================================ @@ -113,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, ): @@ -122,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") @@ -152,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 ), ) @@ -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,16 +225,291 @@ 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 Home + # OMVS Max Files Per Process # ============================================================================ - 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_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 Program + # OMVS Max Non-Shared Memory # ============================================================================ - 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_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 + # ============================================================================ + 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") + self.assertEqual( + 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 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 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) + 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_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..4a3f324b --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..36746060 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..d73d98a3 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..bdab5be8 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..1f9589a3 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..21a29802 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..036f42b0 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..ffc81d57 --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..5b51838c --- /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": null, + "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_directory": { + "value": "/u/squidwrd", + "operation": null + }, + "omvs:default_shell": { + "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..5cd64554 --- /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": null, + "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_directory": { + "value": "/u/clarinet", + "operation": null + }, + "omvs:default_shell": { + "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_log_samples/extract_user_base_omvs_success.log b/tests/user/user_log_samples/extract_user_base_omvs_success.log index f7dc260b..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 @@ -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/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..d40ce005 --- /dev/null +++ b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml @@ -0,0 +1,37 @@ + + + + Squidward + ******** + LEONARD + 10/22/23 + 11/2/23 + + + 10485760 + 1500 + 50 + 4g + 350 + 128 + + 2g + 48 + 1919 + /u/squidward + /bin/sh + + + SB29 + ISPF + A + 2048 + B + PROC + 1024 + O + ABCD + SYSDA + + + \ No newline at end of file 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_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_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_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_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_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/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_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 diff --git a/tests/connection/connection_result_samples/add_connection_result_success.xml b/tests/user/user_result_samples/alter_user_result_extended_success.xml similarity index 53% rename from tests/connection/connection_result_samples/add_connection_result_success.xml rename to tests/user/user_result_samples/alter_user_result_extended_success.xml index 4a45e587..87293679 100644 --- a/tests/connection/connection_result_samples/add_connection_result_success.xml +++ b/tests/user/user_result_samples/alter_user_result_extended_success.xml @@ -1,13 +1,14 @@ - + + Definition exists. Add command skipped due to precheck option 0 0 0 - CONNECT ESWIFT GROUP (TESTGRP0) + 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_bad_attribute_error.json b/tests/user/user_result_samples/extract_user_result_bad_attribute_error.json new file mode 100644 index 00000000..c15ae7cf --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_bad_attribute_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_bad_attribute_error.xml b/tests/user/user_result_samples/extract_user_result_bad_attribute_error.xml new file mode 100644 index 00000000..fc284509 --- /dev/null +++ b/tests/user/user_result_samples/extract_user_result_bad_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/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..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 @@ -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..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 @@ -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 } } ] 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..c035e486 --- /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": "squidward", + "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": null, + "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": 48, + "maxFileMappingPages": 350, + "maxNonSharedMemory": "4g", + "maxSharedMemory": "2g" + }, + "tso": { + "accountNumber": "sb29", + "holdClass": "a", + "messageClass": "b", + "logonProcedure": "proc", + "defaultRegionSize": 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..38e1f9db --- /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=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 + 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= 48 + MMAPAREAMAX= 00000350 + MEMLIMIT= 4G + SHMEMMAX= 2G + + TSO INFORMATION + --------------- + ACCTNUM= SB29 + HOLDCLASS= A + MSGCLASS= B + PROC= PROC + SIZE= 00001024 + MAXSIZE= 00002048 + SYSOUTCLASS= O + UNIT= SYSDA + USERDATA= ABCD + COMMAND= ISPF + + + 0 + 0 + \ No newline at end of file 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 94% 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..db9bb8bc 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": { @@ -35,7 +35,7 @@ "connectDate": "4/4/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_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_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