From 696295207321993cfcd70c6024dab9fb8e7d8b24 Mon Sep 17 00:00:00 2001 From: d-w-moore Date: Sun, 24 Mar 2024 04:16:31 -0400 Subject: [PATCH] [#522][#523] allow '=' and ';' in PAM passwords --- irods/api_number.py | 4 ++- irods/connection.py | 14 ++++---- irods/test/PRC_issue_362.bats | 61 ++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/irods/api_number.py b/irods/api_number.py index 22d6bcf66..2f2a54a11 100644 --- a/irods/api_number.py +++ b/irods/api_number.py @@ -179,5 +179,7 @@ "GET_RESOURCE_INFO_FOR_OPERATION_AN": 10220, "ATOMIC_APPLY_METADATA_OPERATIONS_APN": 20002, "GET_FILE_DESCRIPTOR_INFO_APN": 20000, - "REPLICA_CLOSE_APN": 20004 + "REPLICA_CLOSE_APN": 20004, + + "AUTH_PLUG_REQ_AN": 1201 } diff --git a/irods/connection.py b/irods/connection.py index 4a8ffec0c..45774ca01 100644 --- a/irods/connection.py +++ b/irods/connection.py @@ -25,8 +25,6 @@ from irods.message import (PamAuthRequest, PamAuthRequestOut) - -ALLOW_PAM_LONG_TOKENS = True # True to fix [#279] # Message to be logged when the connection # destructor is called. Used in a unit test DESTRUCTOR_MSG = "connection __del__() called" @@ -490,9 +488,12 @@ def _login_pam(self): if getattr(self,'DISALLOWING_PAM_PLAINTEXT',True): raise PlainTextPAMPasswordError - Pam_Long_Tokens = (ALLOW_PAM_LONG_TOKENS and (len(ctx) >= MAX_NAME_LEN)) + # In general authentication API, a ';' and '=' in the password would be misinterpreted due to those + # characters' special meaning in the context string parameter. + use_dedicated_pam_api = len(ctx) >= MAX_NAME_LEN or \ + {';','='}.intersection(set(new_pam_password)) - if Pam_Long_Tokens: + if use_dedicated_pam_api: message_body = PamAuthRequest( pamUser = self.account.client_user, pamPassword = new_pam_password, timeToLive = time_to_live_in_hours) @@ -502,7 +503,7 @@ def _login_pam(self): auth_req = iRODSMessage( msg_type='RODS_API_REQ', msg=message_body, - int_info=(725 if Pam_Long_Tokens else 1201) + int_info=api_number['PAM_AUTH_REQUEST_AN' if use_dedicated_pam_api else 'AUTH_PLUG_REQ_AN'] ) self.send(auth_req) @@ -513,8 +514,7 @@ def _login_pam(self): # TODO (#480): In Python3 will be able to do: 'raise RuntimeError(...) from exc' for more succinct error messages raise RuntimeError('Client-configured TTL is outside server parameters (password min and max times)') - Pam_Response_Class = (PamAuthRequestOut if Pam_Long_Tokens - else AuthPluginOut) + Pam_Response_Class = (PamAuthRequestOut if use_dedicated_pam_api else AuthPluginOut) auth_out = output_message.get_main_message( Pam_Response_Class ) diff --git a/irods/test/PRC_issue_362.bats b/irods/test/PRC_issue_362.bats index c568ad807..1516de365 100644 --- a/irods/test/PRC_issue_362.bats +++ b/irods/test/PRC_issue_362.bats @@ -1,36 +1,45 @@ # The tests in this BATS module must be run as a (passwordless) sudo-enabled user. # It is also required that the python irodsclient be installed under irods' ~/.local environment. +. $BATS_TEST_DIRNAME/scripts/funcs setup() { - local -A chars=( - [semicolon]=";" - [atsymbol]="@" - [equals]="=" - [ampersand]="&" - ) - [ $BATS_TEST_NUMBER = 1 ] && echo "---" >/tmp/PRC_test_issue_362 - local name=${BATS_TEST_DESCRIPTION##*_} - CHR="${chars[$name]}" + + iinit_as_rods + + setup_pam_login_for_user "test123" alice + + cat >~/test_get_home_coll.py <<-EOF + import irods.test.helpers as h + ses = h.make_session() + home_coll = h.home_collection(ses) + exit(0 if ses.collections.get(home_coll).path == home_coll + and ses.pool.account._original_authentication_scheme.lower() in ('pam','pam_password') + else 1) + EOF } -TEST_THE_TEST="" +teardown() { + iinit_as_rods + finalize_pam_login_for_user alice +} prc_test() { - local USER="alissa" - local PASSWORD=$(tr "." "$CHR" <<<"my.pass") - echo "$USER:$PASSWORD" | sudo chpasswd - if [ "$TEST_THE_TEST" = 1 ]; then - echo -n `date`: "" >&2 - { su - "$USER" -c "id" <<<"$PASSWORD" 2>/dev/null | grep $USER ; } >&2 - else - sudo su - irods -c "env PYTHON_IRODSCLIENT_TEST_PAM_PW_OVERRIDE='$PASSWORD' python -m unittest \ - irods.test.login_auth_test.TestLogins.test_escaped_pam_password_chars__362" - fi -} 2>> /tmp/PRC_test_issue_362 - -@test "test_with_atsymbol" { prc_test; } -@test "test_with_semicolon" { prc_test; } -@test "test_with_equals" { prc_test; } -@test "test_with_ampersand" { prc_test; } + local CHR="$1" + ## Arrange for secrets file to be generated internally by the Python client + cat >~/.python_irodsclient <<-EOF + legacy_auth.pam.store_password_to_environment True + legacy_auth.pam.password_for_auto_renew 'my${CHR}pass' + legacy_auth.pam.time_to_live_in_hours 1 + EOF + local USER="alice" + local PASSWORD="my${CHR}pass" + sudo chpasswd <<<"$USER:$PASSWORD" + env PYTHON_IRODSCLIENT_CONFIGURATION_PATH='' python ~/test_get_home_coll.py +} + +@test "test_with_atsymbol" { prc_test "@"; } +@test "test_with_semicolon" { prc_test ";"; } +@test "test_with_equals" { prc_test "="; } +@test "test_with_ampersand" { prc_test "&"; }