irods / python-irodsclient

A Python API for iRODS
Other
62 stars 73 forks source link

password in PAM authentication and irods_environment.json #312

Open gmuscianisi opened 3 years ago

gmuscianisi commented 3 years ago

Dear all, I'm trying to use the python-irodsclient using PAM authentication. My test script is:

import os
from irods.session import iRODSSession

env_file = os.path.expanduser('~/.irods/irods_environment.json')

with iRODSSession(irods_env_file=env_file) as session:

    session.collections.get(mypath).path

where in the irods_environment.json file I have set the "irods_passwords" parameter with my PAM password. I tryed also to set "password" keyword instead of "irods_password".

But, in any case, when I run the script I am not able to authenticate by the error:

FileNotFoundError: [Errno 2] No such file or directory: '~/.irods/.irodsA'

How can I solve this issue? How can I pass the PAM password without typing the "iinit" command?

Thanks in advance. Best regards. Giusy

d-w-moore commented 3 years ago

@gmuscianisi You need to run iinit to authenticate before running the python script. That step should create the ~/.irods/.irodsA file.

gmuscianisi commented 3 years ago

Hi Daniel, thanks for your reply.

Is there a way to avoid to run the iinit command ?

Best regards, Giusy

d-w-moore commented 3 years ago

Does iinit not exist on the client end?

d-w-moore commented 3 years ago

@gmuscianisi If you'd rather not use the environment in ~/.irods, you could alternatively use the inline form of the iRODSSession (host, port, user, zone, password, **ssl_options) , but be aware it's not secure unless SSL is active. (The password value is the actual PAM password in this case, unmasked by any hashing transformation, and it would be sent in the clear!)

gmuscianisi commented 3 years ago

Hi Daniel, my question was born from a user of my iRODS server that would like to use iRODS without the icommand client in his local machine. Thanks for your suggestions. Best regards. Giusy

trel commented 3 years ago

@d-w-moore let's make this issue about documenting this inline-with-pam-with-caveats use case in the README

d-w-moore commented 2 years ago

@gmuscianisi If you are unable to (or not wishing to : ) ) have iinit to run on the client platform, something like the below script might work. (For such purposes, I'm assuming SSL is already enabled on the iRODS server to which we're connecting; otherwise, as I alluded to before, we'd be sending sensitive passwords in the clear):

#!/usr/bin/env python
# iinit_pam_ssl.py
#  Sample usage: python iinit_pam_ssl.py user alice  password alices_pam_password \
#                             host localhost port 1247 zone tempZone 
from getpass import getpass
from irods.password_obfuscation import encode
from irods.session import iRODSSession
from irods.connection import Connection
import json
import os
import sys
import ssl
from os import chmod
from os.path import expanduser,exists,join
from getopt import getopt

home_env_path = expanduser('~/.irods')
env_file_path = join(home_env_path,'irods_environment.json')
auth_file_path = join(home_env_path,'.irodsA')

SSL_options = {
 'irods_client_server_policy': 'CS_NEG_REQUIRE',
 'irods_client_server_negotiation': 'request_server_negotiation',
 'irods_ssl_verify_server': 'none',
 'irods_encryption_key_size': 16,
 'irods_encryption_salt_size': 8,
 'irods_encryption_num_hash_rounds': 16,
 'irods_encryption_algorithm': 'AES-256-CBC'
}

def do_iinit( host, port, user, zone, password ):
    ses = iRODSSession( host=host,
                        user=user,
                        zone=zone,
                        password=password,
                        port=port,
                        authentication_scheme='PAM', ** SSL_options )

    try:
        token = ses.pam_pw_negotiated
    except Exception:
        token = None

    if not os.path.exists( home_env_path ):
        os.mkdir( home_env_path )
        chmod (home_env_path,0o700)

    if isinstance(token ,list) and token:
        with open(auth_file_path,'w') as auth_file:
            auth_file.write(encode(token[0]))
        chmod (auth_file_path,0o600)

    try:
        env = json.load(open(env_file_path))
    except:
        env = {}

    if not(env):
        env['irods_authentication_scheme']='PAM'
        env.update(SSL_options)

    env['irods_user_name'] = user
    env['irods_zone_name'] = zone
    env['irods_port'] = int(port)
    env['irods_host'] = host

    env = json.dump(env,open(env_file_path,'w'))

def get_kv_pairs_from_cmdline(*args):
    arglist = list(args)
    while arglist:
       k = arglist.pop(0)
       v = arglist.pop(0)
       yield k,v

if __name__ == '__main__':
    import sys
    args = sys.argv[1:]
    dct = {k:v for k,v in get_kv_pairs_from_cmdline(*args)}
    do_iinit(**dct)