From 4c08fb3dbeff78d7bf398f3d386e17e871df1e92 Mon Sep 17 00:00:00 2001 From: PierreV23 <77776198+PierreV23@users.noreply.github.com> Date: Mon, 2 Nov 2026 23:54:36 +0100 Subject: [PATCH] [#785] add support for new `irods` authentication scheme --- irods/auth/__init__.py | 12 ++++++- irods/auth/irods_scheme.py | 64 ++++++++++++++++++++++++++++++++++++++ irods/connection.py | 5 +-- irods/exception.py | 4 +++ 4 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 irods/auth/irods_scheme.py diff --git a/irods/auth/__init__.py b/irods/auth/__init__.py index a3c10396a..cee4f19d2 100644 --- a/irods/auth/__init__.py +++ b/irods/auth/__init__.py @@ -7,7 +7,17 @@ import irods.session -__all__ = ["pam_interactive", "pam_password", "native"] +__all__ = ["pam_interactive", "pam_password", "native", "irods_scheme"] + + +# Schemes whose plugin module is not named after the scheme +# The `irods` scheme file (irods.py) would clash with the package name `irods` +# when irods.py get loaded into globals at runtime. +_PLUGIN_MODULE_FOR_SCHEME = {"irods": "irods_scheme"} + + +def plugin_module_name(scheme): + return _PLUGIN_MODULE_FOR_SCHEME.get(scheme, scheme) AUTH_PLUGIN_PACKAGE = "irods.auth" diff --git a/irods/auth/irods_scheme.py b/irods/auth/irods_scheme.py new file mode 100644 index 000000000..3e1cd25c7 --- /dev/null +++ b/irods/auth/irods_scheme.py @@ -0,0 +1,64 @@ +import ssl + +from . import ( + __NEXT_OPERATION__, + CLIENT_GET_REQUEST_RESULT, + _auth_api_request, + authentication_base, +) +from .pam_password import ENSURE_SSL_IS_ACTIVE + +_scheme = "irods" + + +def login(conn, **extra_opt): + request = { + "user_name": conn.account.proxy_user, + "zone_name": conn.account.proxy_zone + } + request.update(extra_opt) + _irods_ClientAuthState(conn, scheme=_scheme).authenticate_client(initial_request=request) + + +class _irods_ClientAuthState(authentication_base): + def auth_client_start(self, request): + self._token_result = request.pop(CLIENT_GET_REQUEST_RESULT, None) + + if request.pop(ENSURE_SSL_IS_ACTIVE, True) and not isinstance(self.conn.socket, ssl.SSLSocket): + msg = "irods auth scheme requires secure communications (TLS/SSL) with the server." + raise RuntimeError(msg) + + resp = request.copy() + resp[__NEXT_OPERATION__] = "client_init_auth_with_server" + return resp + + def client_init_auth_with_server(self, request): + server_req = request.copy() + server_req[__NEXT_OPERATION__] = "server_prepare_auth_check" + resp = _auth_api_request(self.conn, server_req) + + # set with set_auth_option_for_scheme("irods", "session_token", ...) + if "session_token" in resp: + resp[__NEXT_OPERATION__] = "client_auth_with_session_token" + else: + resp["password"] = self.conn.account.password or "" + resp[__NEXT_OPERATION__] = "client_auth_with_password" + return resp + + def client_auth_with_password(self, request): + server_req = request.copy() + server_req[__NEXT_OPERATION__] = "server_auth_with_password" + resp = _auth_api_request(self.conn, server_req) + + if isinstance(self._token_result, list): + self._token_result[:] = (resp["session_token"],) + + resp[__NEXT_OPERATION__] = "client_auth_with_session_token" + return resp + + def client_auth_with_session_token(self, request): + server_req = request.copy() + server_req[__NEXT_OPERATION__] = "server_auth_with_session_token" + resp = _auth_api_request(self.conn, server_req) + self.loggedIn = 1 + return resp diff --git a/irods/connection.py b/irods/connection.py index 9d02e1523..40087fb3a 100644 --- a/irods/connection.py +++ b/irods/connection.py @@ -103,8 +103,9 @@ def __init__(self, pool, account): auth_module = None # use client side "plugin" module: irods.auth. - irods.auth.load_plugins(subset=[scheme]) - auth_module = getattr(irods.auth, scheme, None) + module_name = irods.auth.plugin_module_name(scheme) + irods.auth.load_plugins(subset=[module_name]) + auth_module = getattr(irods.auth, module_name, None) if auth_module: auth_module.login(self, **self.auth_options) auth_type = auth_module.__name__ diff --git a/irods/exception.py b/irods/exception.py index 8ee119771..438041039 100644 --- a/irods/exception.py +++ b/irods/exception.py @@ -676,6 +676,10 @@ class SYS_NOT_ALLOWED(iRODSException): code = -169000 +class AUTHENTICATION_ERROR(iRODSException): + code = -178000 + + class UserInputException(iRODSException): pass