Source code for sdss_brain.auth.user

# !/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 Cherinka


from __future__ import print_function, division, absolute_import

from sdss_brain.auth import Netrc, Htpass
from sdss_brain.exceptions import BrainError
from sdss_brain.api.io import send_post_request

try:
    from collaboration.wiki import Credential
except ImportError:
    Credential = None


[docs]class User(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 = user self.netrc = None self.htpass = None self.cred = None self.member = None self._valid_netrc = False self._valid_htpass = False self._valid_sdss_cred = False self._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): return self.user def _setup_auths(self): """ Setup the authenticators """ # setup netrc try: self.netrc = Netrc() except BrainError: self.netrc = None else: self._valid_netrc = (self.user in self.netrc.read_netrc('data.sdss.org') or self.user in self.netrc.read_netrc('api.sdss.org')) # setup htpass try: self.htpass = Htpass() except BrainError: self.htpass = None else: self._valid_htpass = False # setup SDSS Credential if Credential: self.cred = Credential @property def is_netrc_valid(self) -> bool: """ Checks if the netrc credentials are validated for the given user """ return False if not self.netrc else self._valid_netrc @property def is_htpass_valid(self) -> bool: """ Checks if htpasswd credentials are validated for the given user """ return False if not self.htpass else self._valid_htpass @property def is_sdss_cred_valid(self) -> bool: """ Checks if SDSS credentials are validated for the given user """ return self._valid_sdss_cred @property def validated(self) -> bool: """ Checks if user is validated """ return any([self.is_netrc_valid, self.is_htpass_valid, self.is_sdss_cred_valid]) @property def in_sdss(self) -> dict: """ Checks member status in SDSS-IV and SDSS-V """ if self.member: return {'sdss4': self.member['sdss4']['has_sdss_access'], 'sdss5': self.member['sdss5']['has_sdss_access']}
[docs] def validate_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 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 netrc if self.is_netrc_valid: try: user, passwd = self.netrc.read_netrc('data.sdss.org') except ValueError: user, passwd = self.netrc.read_netrc('api.sdss.org') if user != self.user: raise ValueError(f'netrc user {user} mismatched with input user {self.user}!') # if no password set, use the netrc password password = passwd if not password else password # ensure a password is specified if not password: raise ValueError('Must provide a password if none extracted from netrc.') # validate the htpasswd if self.htpass: self._valid_htpass = self.htpass.validate_user(self.user, password) or False # try to validate using SDSS Credentials if self.cred: cred = Credential(self.user, password) cred.authenticate_via_trac() self._valid_sdss_cred = cred.authenticated is True else: # TODO change this dev login to production site when ready cred_url = 'https://internal.sdss.org/dev/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)