X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/4fc613797f88dbb33c234ba7cd13965b1236bfee..a70f39f361c3c60018b90f02af64525534025e09:/sdk/pam/arvados_pam/__init__.py diff --git a/sdk/pam/arvados_pam/__init__.py b/sdk/pam/arvados_pam/__init__.py index 4db6e58b12..087ea2e9fa 100644 --- a/sdk/pam/arvados_pam/__init__.py +++ b/sdk/pam/arvados_pam/__init__.py @@ -1,119 +1,36 @@ import sys sys.argv=[''] -import arvados -import os -import syslog - -def auth_log(msg): - """Send errors to default auth log""" - syslog.openlog(facility=syslog.LOG_AUTH) - syslog.syslog('arvados_pam: ' + msg) - syslog.closelog() - -def config_file(): - return file('/etc/default/arvados_pam') - -def config(): - txt = config_file().read() - c = dict() - for x in txt.splitlines(False): - if not x.strip().startswith('#'): - kv = x.split('=', 2) - c[kv[0].strip()] = kv[1].strip() - return c - -class AuthEvent(object): - def __init__(self, client_host, api_host, shell_host, username, token): - self.client_host = client_host - self.api_host = api_host - self.shell_hostname = shell_host - self.username = username - self.token = token - self.vm = None - self.user = None - - def can_login(self): - ok = False - try: - self.arv = arvados.api('v1', host=self.api_host, token=self.token, cache=None) - self._lookup_vm() - if self._check_login_permission(): - self.result = 'Authenticated' - ok = True - else: - self.result = 'Denied' - except Exception as e: - self.result = 'Error: ' + repr(e) - auth_log(self.message()) - return ok - - def _lookup_vm(self): - """Load the VM record for this host into self.vm. Raise if not possible.""" - - vms = self.arv.virtual_machines().list(filters=[['hostname','=',self.shell_hostname]]).execute() - if vms['items_available'] > 1: - raise Exception("ambiguous VM hostname matched %d records" % vms['items_available']) - if vms['items_available'] == 0: - raise Exception("VM hostname not found") - self.vm = vms['items'][0] - if self.vm['hostname'] != self.shell_hostname: - raise Exception("API returned record with wrong hostname") - - def _check_login_permission(self): - """Check permission to log in. Return True if permission is granted.""" - self._lookup_vm() - self.user = self.arv.users().current().execute() - filters = [ - ['link_class','=','permission'], - ['name','=','can_login'], - ['head_uuid','=',self.vm['uuid']], - ['tail_uuid','=',self.user['uuid']]] - for l in self.arv.links().list(filters=filters, limit=10000).execute()['items']: - if (l['properties']['username'] == self.username and - l['tail_uuid'] == self.user['uuid'] and - l['head_uuid'] == self.vm['uuid'] and - l['link_class'] == 'permission' and - l['name'] == 'can_login'): - return True - return False - - def message(self): - if len(self.token) > 40: - log_token = self.token[0:15] - else: - log_token = '' - log_label = [self.client_host, self.api_host, self.shell_hostname, self.username, log_token] - if self.vm: - log_label += [self.vm.get('uuid')] - if self.user: - log_label += [self.user.get('uuid'), self.user.get('full_name')] - return str(log_label) + ': ' + self.result - +from . import auth_event def pam_sm_authenticate(pamh, flags, argv): + config = {} + config['arvados_api_host'] = argv[1] + config['virtual_machine_hostname'] = argv[2] + if len(argv) > 3: + for k in argv[3:]: + config[k] = True + try: - user = pamh.get_user() - except pamh.exception as e: + username = pamh.get_user(None) + except pamh.exception, e: return e.pam_result - if not user: + if not username: return pamh.PAM_USER_UNKNOWN try: - resp = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, '')) + prompt = '' if config.get('noprompt') else 'Arvados API token: ' + token = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, prompt)).resp except pamh.exception as e: return e.pam_result - try: - config = config() - api_host = config['ARVADOS_API_HOST'].strip() - shell_host = config['HOSTNAME'].strip() - except Exception as e: - auth_log("loading config: " + repr(e)) - return False - - if AuthEvent(pamh.rhost, api_host, shell_host, user, resp.resp).can_login(): + if auth_event.AuthEvent( + config=config, + service=pamh.service, + client_host=pamh.rhost, + username=username, + token=token).can_login(): return pamh.PAM_SUCCESS else: return pamh.PAM_AUTH_ERR