# !/usr/bin/env python# -*- coding: utf-8 -*-## Filename: user.py# Project: auth# Author: Brian Cherinka# Created: Thursday, 22nd October 2020 11:17:33 am# License: BSD 3-clause "New" or "Revised" License# Copyright (c) 2020 Brian Cherinka# Last Modified: Thursday, 22nd October 2020 11:17:33 am# Modified By: Brian Cherinkafrom__future__importprint_function,division,absolute_importfromsdss_brain.authimportNetrc,Htpassfromsdss_brain.exceptionsimportBrainErrorfromsdss_brain.api.ioimportsend_post_requesttry:fromcollaboration.wikiimportCredentialexceptImportError:Credential=None
[docs]classUser(object):""" Class representing a valid user This class represents a valid SDSS user. It checks and validates the user against a local netrc file, a local htpasswd file, and against the SDSS collaboration.Credentials. Parameters ---------- user : str the SDSS username Attributes ---------- member : dict dictionary of member information for a validated user netrc : type[Netrc] A local Netrc instance, if any htpass : type[Htpass] A local Htpass instance, if any cred : type[Credential] A local SDSS Credential instance, if any """def__init__(self,user:str):self.user=userself.netrc=Noneself.htpass=Noneself.cred=Noneself.member=Noneself._valid_netrc=Falseself._valid_htpass=Falseself._valid_sdss_cred=Falseself._validated_netrc_host=Noneself._setup_auths()def__repr__(self)->str:return(f'<User("{self.user}", netrc={self.is_netrc_valid}, htpass={self.is_htpass_valid}, 'f'cred={self.is_sdss_cred_valid})>')def__str__(self):returnself.userdef_setup_auths(self):""" Setup the authenticators """# setup netrctry:self.netrc=Netrc()exceptBrainError:self.netrc=Noneelse:net_hosts=['data.sdss.org','api.sdss.org','data.sdss5.org','wiki.sdss.org']self._valid_netrc=any(self.userinself.netrc.read_netrc(vhost:=h)forhinnet_hosts)self._validated_netrc_host=vhostifself._valid_netrcelseNone# self._valid_netrc = (self.user in self.netrc.read_netrc('data.sdss.org') or# self.user in self.netrc.read_netrc('api.sdss.org') or# self.user in self.netrc.read_netrc('data.sdss5.org') or# self.user in self.netrc.read_netrc('wiki.sdss.org'))# setup htpasstry:self.htpass=Htpass()exceptBrainError:self.htpass=Noneelse:self._valid_htpass=False# setup SDSS CredentialifCredential:self.cred=Credential@propertydefis_netrc_valid(self)->bool:""" Checks if the netrc credentials are validated for the given user """returnself._valid_netrcifself.netrcelseFalse@propertydefis_htpass_valid(self)->bool:""" Checks if htpasswd credentials are validated for the given user """returnself._valid_htpassifself.htpasselseFalse@propertydefis_sdss_cred_valid(self)->bool:""" Checks if SDSS credentials are validated for the given user """returnself._valid_sdss_cred@propertydefvalidated(self)->bool:""" Checks if user is validated """returnany([self.is_netrc_valid,self.is_htpass_valid,self.is_sdss_cred_valid])@propertydefin_sdss(self)->dict:""" Checks member status in SDSS-IV and SDSS-V """ifself.member:return{'sdss4':self.member['sdss4']['has_sdss_access'],'sdss5':self.member['sdss5']['has_sdss_access']}
[docs]defvalidate_user(self,password:str=None)->None:""" Validate the given user Validates the given user for netrc, htpass, and SDSS Credential authentication. Attempts to extract a valid password from the netrc file for the given user. Otherwise a password must be explicitly input. Parameters ---------- password : str, optional The password for the given user, by default None Raises ------ ValueError when no matching user can be found in the netrc file ValueError when the netrc username does not match the input user ValueError when no valid password is input nor extracted from the netrc """# look up user info from validated netrcifself.is_netrc_valid:forhostinself.netrc.allowed_hosts:try:user,passwd=self.netrc.read_netrc(host)exceptValueError:passelse:self._validated_netrc_host=host# on successful user, break out of loopbreak# if there is no user, failifnotuser:raiseValueError('No user found for any of the allowed netrc hosts.')# if users are mismatched, failifuser!=self.user:raiseValueError(f'netrc user {user} mismatched with input user {self.user}!')# if no password set, use the netrc passwordpassword=passwordorpasswd# ensure a password is specifiedifnotpassword:raiseValueError('Must provide a password if none extracted from netrc.')# validate the htpasswdifself.htpass:self._valid_htpass=self.htpass.validate_user(self.user,password)orFalse# try to validate using SDSS Credentialsifself.cred:cred=Credential(self.user,password)cred.authenticate_via_trac()self._valid_sdss_cred=cred.authenticatedisTrueelse:cred_url='https://internal.sdss.org/collaboration/api/login'data=send_post_request(cred_url,data={'username':self.user,'password':password})self._valid_sdss_cred=data.get('authenticated',False)=='True'self.member=data.get('member',None)