Skip to content

[#621] write .irodsA file with encoded passwords #622

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ iCommands.
Caveat for iRODS 4.3+: when upgrading from 4.2, the "irods_authentication_scheme" setting must be changed from "pam" to "pam_password" in
`~/.irods/irods_environment.json` for all file-based client environments.

To replicate iinit's capability for creating valid PAM login credentials file (.irodsA) for the client login environment, we can set these
two configuration variables:

```
legacy_auth.pam.password_for_auto_renew "my_pam_password"
legacy_auth.pam.store_password_to_environment True
```

Optionally, the `legacy_auth.pam.time_to_live_in_hours` may also be set to determine the time-to-live for the new password.
Leaving it at the default value defers this decision to the server.

Maintaining a connection
------------------------

Expand Down
12 changes: 11 additions & 1 deletion irods/account.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import os

class iRODSAccount(object):

@property
def derived_auth_file(self):
return '' if not self.env_file else os.path.join(os.path.dirname(self.env_file),'.irodsA')

def __init__(self, irods_host, irods_port, irods_user_name, irods_zone_name,
irods_authentication_scheme='native',
password=None, client_user=None,
server_dn=None, client_zone=None, **kwargs):
server_dn=None, client_zone=None,
env_file = '',
**kwargs):


# Allowed overrides when cloning sessions. (Currently hostname only.)
for k,v in kwargs.pop('_overrides',{}).items():
if k =='irods_host':
irods_host = v

self.env_file = env_file
tuplify = lambda _: _ if isinstance(_,(list,tuple)) else (_,)
schemes = [_.lower() for _ in tuplify(irods_authentication_scheme)]

Expand Down
33 changes: 33 additions & 0 deletions irods/client_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import irods.client_configuration as cfg
import irods.password_obfuscation as obf
import irods.helpers as h
import getpass
import sys

def write_credentials_with_native_password( password ):
s = h.make_session()
assert(not s.auth_file)
open(s.pool.account.derived_auth_file,'w').write(obf.encode(password))
return True

def write_credentials_with_pam_password( password ):
s = h.make_session()
assert(not s.auth_file)
s.pool.account.password = password
with cfg.loadlines( [dict(setting='legacy_auth.pam.password_for_auto_renew',value='')] ):
to_encode = s.pam_pw_negotiated
if to_encode:
open(s.pool.account.derived_auth_file,'w').write(obf.encode(to_encode[0]))
return True
return False

if __name__ == '__main__':
vector = {
'pam': write_credentials_with_pam_password,
'native': write_credentials_with_native_password,
}

if sys.argv[1] in vector:
vector[sys.argv[1]](getpass.getpass(prompt=f'{sys.argv[1]} password: '))
else:
print('did not recognize authentication scheme argument',file = sys.stderr)
5 changes: 3 additions & 2 deletions irods/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,9 @@ def _login_pam(self):
self._login_native(password = auth_out.result_)

# Store new password in .irodsA if requested.
if self.account._auth_file and cfg.legacy_auth.pam.store_password_to_environment:
with open(self.account._auth_file,'w') as f:
auth_file = (self.account._auth_file or self.account.derived_auth_file)
if auth_file and cfg.legacy_auth.pam.store_password_to_environment:
with open(auth_file,'w') as f:
f.write(obf.encode(auth_out.result_))
logger.debug('new PAM pw write succeeded')

Expand Down
15 changes: 9 additions & 6 deletions irods/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,9 @@ def cleanup(self, new_host = ''):
self.__configured = self.configure(**self.do_configure)

def _configure_account(self, **kwargs):

env_file = None
try:
env_file = kwargs['irods_env_file']

except KeyError:
# For backward compatibility
for key in ['host', 'port', 'authentication_scheme']:
Expand All @@ -232,6 +231,9 @@ def _configure_account(self, **kwargs):
# Update with new keywords arguments only
creds.update((key, value) for key, value in kwargs.items() if key not in creds)

if env_file:
creds['env_file'] = env_file

# Get auth scheme
try:
auth_scheme = creds['irods_authentication_scheme']
Expand Down Expand Up @@ -259,10 +261,11 @@ def _configure_account(self, **kwargs):
missing_file_path = []
error_args = []
pw = creds['password'] = self.get_irods_password(session_ = self, file_path_if_not_found = missing_file_path, **creds)
if not pw and creds.get('irods_user_name') != 'anonymous':
if missing_file_path:
error_args += ["Authentication file not found at {!r}".format(missing_file_path[0])]
raise NonAnonymousLoginWithoutPassword(*error_args)
if auth_scheme.lower() not in PAM_AUTH_SCHEMES:
if not pw and creds.get('irods_user_name') != 'anonymous':
if missing_file_path:
error_args += ["Authentication file not found at {!r}".format(missing_file_path[0])]
raise NonAnonymousLoginWithoutPassword(*error_args)

return iRODSAccount(**creds)

Expand Down