class FlatFileAuthenticationBackend(BaseAuthenticationBackend): """ Backend which reads authentication information from a local file. Entries need to be in a htpasswd file like format. This means entries can be managed with the htpasswd utility (https://httpd.apache.org/docs/current/programs/htpasswd.html) which ships with Apache HTTP server. Note: This backends depends on the "passlib" library. """ def __init__(self, file_path): """ :param file_path: Path to the file with authentication information. :type file_path: ``str`` """ self._file_path = file_path self._htpasswd_file = HtpasswdFile(path=self._file_path) def authenticate(self, username, password): result = self._htpasswd_file.check_password(username, password) if result is None: LOG.debug('User "%s" doesn\'t exist' % (username)) elif result is False: LOG.debug('Invalid password for user "%s"' % (username)) elif result is True: LOG.debug('Authentication for user "%s" successful' % (username)) return bool(result) def get_user(self, username): pass
def validate_user(username, password, htpassfile=None, session={}, request=None): ''' Validate the User with htpassfile or Trac ''' from brain import bconfig result = {} # validate the user with htpassfile or trac username is_valid = False user = None # try from request if not htpassfile and request: htpassfile = request.environ.get('HTPASSFILE', None) # try from brain config if not htpassfile and hasattr(bconfig, '_htpass_path'): htpassfile = bconfig._htpass_path # validate user if username == 'sdss': if htpassfile: htpass = HtpasswdFile(htpassfile) is_valid = htpass.check_password(username, password) user = username else: result['error'] = 'No valid htpasswd file found!' else: result = inspection_authenticate(session, username=username, password=password) is_valid = result['is_valid'] user = result.get('membername', None) return is_valid, user, result
def verify_pw(username, password): """ return password or None if there isn't one""" credentials = HtpasswdFile(app.config["CREDENTIAL_FILE"]) if not credentials.check_password(username, password): logging.warning("%s tried to login with wrong password", username) return False return True
class HtpasswdAuthenticator(object): """ Handles the user authentication for htpasswd files htpasswd is the location of the htpasswd to use """ def __init__(self): #try to locate the server config and load it server_folder = os.path.join(os.path.expanduser("~"), '.conan_server') server_conf = os.path.join(server_folder, "server.conf") htpasswd_location = os.path.join(server_folder, "plugins", "authentication", ".htpasswd") if os.path.exists(server_conf): conf = ConfigParser() conf.read(server_conf) new_loc = conf.get("server", "htpasswd_file") if os.path.exists(new_loc): htpasswd_location = new_loc self.htpasswd = HtpasswdFile(htpasswd_location) def valid_user(self, username, plain_password): """ username: Username to be authenticated plain_password: The password to authenticate with return: True if match False if don't """ # Update self.htpasswd.load_if_changed() # Verify return username in self.htpasswd.users() and \ self.htpasswd.check_password(username, plain_password)
def groupfinder(username, password, request): ht = HtpasswdFile() ht.load_string(os.environ.get("HTPASSWORDS", "")) if ht.check_password(username, password): return ["admin"] else: return None
def is_user_authenticated(self, username, password): passfile = HtpasswdFile(config['passfile']) # is the user in the password file? if not username in passfile.users(): return False return passfile.check_password(username, password)
def authenticate(self, request): """Authenticate the provided request.""" if (self.config.password_file is None or self.config.password_file == '.'): return True pwd_file = HtpasswdFile(self.config.password_file) pwd_file.load_if_changed() return pwd_file.check_password(*request.auth)
def test_make_htpasswd(self): self.server.add_user('testuser', 'testpass') self.server.add_user('xtestuser', 'xtestpass') with NamedTemporaryFile() as file: self.server.make_htpasswd(file.name) ht = HtpasswdFile(file.name) self.assertEqual(['testuser', 'xtestuser'], sorted(ht.users())) self.assertTrue(ht.check_password('testuser', 'testpass'))
class HtpasswdUsers(Component): implements(IUserAuthenticator) implements(IUserTranslator) implements(IUserStore) def __init__(self): config = self.get_component_config() if 'file' not in config: raise InsufficientConfiguration(missing='file', component=self.get_component_name()) self.htpasswd = HtpasswdFile(config['file']) def username_to_user(self, username): self.htpasswd.load_if_changed() if username in self.htpasswd.users(): return HtpasswdUser(self, username, username=username, full_name=username) def userid_to_user(self, userid): if userid is None or userid == '*': warnings.warn("You should not call this directly. Use cydra.get_user()", DeprecationWarning, stacklevel=2) return self.compmgr.get_user(userid='*') self.htpasswd.load_if_changed() if userid in self.htpasswd.users(): return HtpasswdUser(self, userid, username=userid, full_name=userid) else: # since the client was looking for a specific ID, # we return a dummy user object with empty data return User(self, userid, full_name='N/A') def groupid_to_group(self, groupid): pass def user_password(self, user, password): self.htpasswd.load_if_changed() return self.htpasswd.check_password(user.userid, password) def create_user(self, **kwargs): self.htpasswd.load_if_changed() userid = None if 'id' in kwargs: userid = kwargs['id'] elif 'username' in kwargs: userid = kwargs['username'] else: raise ValueError("No username/id specified") if userid in self.htpasswd.users(): raise ValueError("User with this id already exists") else: self.htpasswd.set_password(userid, hashlib.sha1(os.urandom(8)).hexdigest()) self.htpasswd.save() return userid
class UserDB(): def __init__(self, filename): self.htpasswd = HtpasswdFile(filename) def get_users(self): self.htpasswd.get_users() def check_password(self, user, password): return self.htpasswd.check_password(user, password)
def present(dest, username, password, crypt_scheme, create, check_mode): """ Ensures user is present Returns (msg, changed) """ if crypt_scheme in apache_hashes: context = htpasswd_context else: context = CryptContext(schemes=[crypt_scheme] + apache_hashes) if not os.path.exists(dest): if not create: raise ValueError('Destination %s does not exist' % dest) if check_mode: return ("Create %s" % dest, True) create_missing_directories(dest) if LooseVersion(passlib.__version__) >= LooseVersion('1.6'): ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, context=context) else: ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, context=context) if getattr(ht, 'set_password', None): ht.set_password(username, password) else: ht.update(username, password) ht.save() return ("Created %s and added %s" % (dest, username), True) else: if LooseVersion(passlib.__version__) >= LooseVersion('1.6'): ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, context=context) else: ht = HtpasswdFile(dest, default=crypt_scheme, context=context) found = None if getattr(ht, 'check_password', None): found = ht.check_password(username, password) else: found = ht.verify(username, password) if found: return ("%s already present" % username, False) else: if not check_mode: if getattr(ht, 'set_password', None): ht.set_password(username, password) else: ht.update(username, password) ht.save() return ("Add/update %s" % username, True)
def check_credentials(self, username, password): """ Need to make this file based. """ if os.path.isfile(self.htpasswd): ht = HtpasswdFile(self.htpasswd) if ht.check_password(username, password): return (True) else: return (u"Incorrect username or password.") return (u"Htpasswd file was not found ")
def verify_password(login, password): try: htpasswd_file = HtpasswdFile(current_app.config['HTPASSWD_PATH']) except EnvironmentError: return False if htpasswd_file.check_password(login, password): return True else: g.reason = 'invalid password' return False
def authenticate(self, username, password): htpasswd_file = HtpasswdFile(path=self._file_path) result = htpasswd_file.check_password(username, password) if result is None: LOG.debug('User "%s" doesn\'t exist' % (username)) elif result is False: LOG.debug('Invalid password for user "%s"' % (username)) elif result is True: LOG.debug('Authentication for user "%s" successful' % (username)) return bool(result)
class PassManHtpasswd: """ Read usernames and passwords from an htpasswd file """ def __init__(self, path): """ Raises ValueError if htpasswd file is invalid. """ self.htpasswd = HtpasswdFile(path) def test(self, username, password_token): return bool(self.htpasswd.check_password(username, password_token))
def check_auth(username, password): """This function is called to check if a username / password combination is valid. """ if htpasswd is None: logging.warning("htpasswd not initialized, denying") return False if htpasswd is False: logging.info("htpasswd skipped, because it is set to False") return True ht = HtpasswdFile(htpasswd) return ht.check_password(username, password)
def authenticate_credentials(self, key): ht = HtpasswdFile(settings.PATH_TO_HTPASSWD_FILE) usernames = ht.users() for username in usernames: check_result = ht.check_password(username, key) if check_result: if username == usernames[0]: return (self.get_user('admin'), key) else: return (self.get_user(username), key) raise exceptions.AuthenticationFailed('Invalid token.')
def validate_user(username, password, htpassfile=None, request=None): ''' Validate the User with htpassfile or Trac Tries to validate a user first with a user login from the htpassfile, and second from a Trac wiki account. Parameters: username (str): The login user id password (str): The login user password htpassfile (str): Optional. The full path to an htpassfile. request (Request): The Flask request object Returns: A tuple of (boolean if the user is valid, the username, and the results dictionary) ''' from brain import bconfig result = {} # validate the user with htpassfile or trac username is_valid = False user = None # try from request if not htpassfile and request: htpassfile = request.environ.get('HTPASSFILE', None) # try from brain config if not htpassfile and hasattr(bconfig, '_htpass_path'): htpassfile = bconfig._htpass_path # validate user if username == 'sdss': if htpassfile: htpass = HtpasswdFile(htpassfile) is_valid = htpass.check_password(username, password) user = username else: result['error'] = 'No valid htpasswd file found!' else: result = collaboration_authenticate(username=username, password=password) is_valid = result['is_valid'] user = result.get('user', None) return is_valid, user, result
def _htpasswd(username, password, **kwargs): ''' Provide authentication via Apache-style htpasswd files ''' from passlib.apache import HtpasswdFile pwfile = HtpasswdFile(kwargs['filename']) # passlib below version 1.6 uses 'verify' function instead of 'check_password' if salt.utils.version_cmp(kwargs['passlib_version'], '1.6') < 0: return pwfile.verify(username, password) else: return pwfile.check_password(username, password)
class Auth(dnscherry.auth.Auth): def __init__(self, config, logger=None): self.logout_button = True self.htpasswdfile = self._get_param('auth.htpasswd.file', config, None) self.ht = HtpasswdFile(self.htpasswdfile) def check_credentials(self, username, password): try: return self.ht.check_password(username, password) # older versions of passlib doesn't have check_password except AttributeError: username = str(username) password = str(password) return self.ht.verify(username, password)
def authenticate_credentials(self, userid, password, request=None): ht = HtpasswdFile(settings.PATH_TO_HTPASSWD_FILE) result = ht.check_password(userid, password) usernames = ht.users() if result is None: raise exceptions.AuthenticationFailed('Invalid username.') elif not result: raise exceptions.AuthenticationFailed('Invalid password.') else: if userid == usernames[0]: return (self.get_user('admin'), None) else: return (self.get_user(userid), None)
class TestAuthnz(object): def __init__(self, htpasswd_file=".htpasswd", perms_file=".repoperms", keys_file=".rsakeys"): self.htpasswd = HtpasswdFile(htpasswd_file) self.perms_file = perms_file self.keys_file = keys_file def can_read(self, username, path_info): return self._check_access(username, path_info, "r") def can_write(self, username, path_info): return self._check_access(username, path_info, "w") def _check_access(self, username, path_info, level): if username is None: username = "******" if path_info['repository_fs_path'] is None: return False repo = os.path.basename(path_info['repository_fs_path']) config = SafeConfigParser() config.read(self.perms_file) if not config.has_option(repo, username): return False return level in config.get(repo, username) def check_password(self, username, password): self.htpasswd.load_if_changed() return self.htpasswd.check_password(username, password) def check_publickey(self, username, keyblob): with open(self.keys_file, 'rb') as f: for line in f: try: user, key = line.split(':', 1) if (username == user.strip() and keyblob == keys.Key.fromString(data=key.strip() ).blob()): return True except: log.err(None, "Loading key failed") return False
def check_user(self, username, password): """ Verify if the username and password are valid and the user can be authenticated against the htpasswd file properly. :param username: the username that matches the user in the htpasswd file. :param password: the password that will be hashed and verified against the htpasswd file. :return: The user itself. """ ht = HtpasswdFile(HTPASSWD_FILE) if username in ht.users(): if ht.check_password(username, password): return self return False
class TestAuthnz(object): def __init__(self, htpasswd_file=".htpasswd", perms_file=".repoperms", keys_file=".rsakeys"): self.htpasswd = HtpasswdFile(htpasswd_file) self.perms_file = perms_file self.keys_file = keys_file def can_read(self, username, path_info): return self._check_access(username, path_info, "r") def can_write(self, username, path_info): return self._check_access(username, path_info, "w") def _check_access(self, username, path_info, level): if username is None: username = "******" if path_info['repository_fs_path'] is None: return False repo = os.path.basename(path_info['repository_fs_path']) config = SafeConfigParser() config.read(self.perms_file) if not config.has_option(repo, username): return False return level in config.get(repo, username) def check_password(self, username, password): self.htpasswd.load_if_changed() return self.htpasswd.check_password(username, password) def check_publickey(self, username, keyblob): with open(self.keys_file, 'rb') as f: for line in f: try: user, key = line.split(':', 1) if (username == user.strip() and keyblob == keys.Key.fromString(data=key.strip()).blob()): return True except: log.err(None, "Loading key failed") return False
def present(dest, username, password, crypt_scheme, create, check_mode): """ Ensures user is present Returns (msg, changed) """ if crypt_scheme in apache_hashes: context = htpasswd_context else: context = CryptContext(schemes = [ crypt_scheme ] + apache_hashes) if not os.path.exists(dest): if not create: raise ValueError('Destination %s does not exist' % dest) if check_mode: return ("Create %s" % dest, True) create_missing_directories(dest) if StrictVersion(passlib.__version__) >= StrictVersion('1.6'): ht = HtpasswdFile(dest, new=True, default_scheme=crypt_scheme, context=context) else: ht = HtpasswdFile(dest, autoload=False, default=crypt_scheme, context=context) if getattr(ht, 'set_password', None): ht.set_password(username, password) else: ht.update(username, password) ht.save() return ("Created %s and added %s" % (dest, username), True) else: if StrictVersion(passlib.__version__) >= StrictVersion('1.6'): ht = HtpasswdFile(dest, new=False, default_scheme=crypt_scheme, context=context) else: ht = HtpasswdFile(dest, default=crypt_scheme, context=context) found = None if getattr(ht, 'check_password', None): found = ht.check_password(username, password) else: found = ht.verify(username, password) if found: return ("%s already present" % username, False) else: if not check_mode: if getattr(ht, 'set_password', None): ht.set_password(username, password) else: ht.update(username, password) ht.save() return ("Add/update %s" % username, True)
def validate(self): """Validate the needed fields.""" rv = Form.validate(self) if not rv: return False ht = HtpasswdFile(HTPASSWD_FILE) if self.name.data in ht.users(): if ht.check_password(self.name.data, self.passwd.data): ht.set_password(self.name.data, self.newpwd.data) ht.save() return True else: self.passwd.errors.append('Senha Incorreta') return False else: self.name.errors.append('Usuário Desconhecido') return False
class __FileAuthenticator: '''Takes a htpasswd file path from the HTPASSWD_FILE environment variable. ''' def __init__(self, filename): self.filename = filename self.data = HtpasswdFile(self.filename) def authenticate(self, username, password): """ Returns True if username exists and password is valid, False otherwise """ if self.data.check_password(username, password): # Note: check_password returns None if username does not exists return True return False def get_hash(self, username): """ Returns a hash if username exists, None otherwise """ return self.data.get_hash(username) def find_user(self, username): """ Returns True if usename exists in db, False otherwise """ return username in self.data.users()
class HtpasswdUsers(Component): implements(IUserAuthenticator) implements(IUserTranslator) def __init__(self): config = self.get_component_config() if 'file' not in config: raise InsufficientConfiguration(missing='file', component=self.get_component_name()) self.htpasswd = HtpasswdFile(config['file']) def username_to_user(self, username): self.htpasswd.load_if_changed() if username in self.htpasswd.users(): return User(self.compmgr, username, username=username, full_name=username) def userid_to_user(self, userid): if userid is None or userid == '*': warnings.warn("You should not call this directly. Use cydra.get_user()", DeprecationWarning, stacklevel=2) return User(self.compmgr, '*', username='******', full_name='Guest') self.htpasswd.load_if_changed() if userid in self.htpasswd.users(): return User(self.compmgr, userid, username=userid, full_name=userid) else: # since the client was looking for a specific ID, # we return a dummy user object with empty data return User(self.compmgr, userid, full_name='N/A') def groupid_to_group(self, groupid): pass def user_password(self, user, password): self.htpasswd.load_if_changed() return self.htpasswd.check_password(user.userid, password)
class ApachePasswordDB(object): """ Very simple glue between passlib.apache.HtpasswdFile to make it an ICredentialsChecker in Twisted. """ implements(ICredentialsChecker) # we can only implement non-hashing functions as the passwords # may be hashed. credentialInterfaces = ( credentials.IUsernamePassword, ) def __init__(self, filename): self._ht = HtpasswdFile(filename) def requestAvatarId(self, c): if self._ht.check_password(c.username, c.password): # success, return username return defer.succeed(c.username) else: # bad credentials return defer.fail(error.UnauthorizedLogin())
class AuthChecker: methods = [None, 'basic'] def __init__(self, conf): auth = conf.get('auth') if auth not in AuthChecker.methods: raise ValueError('unknown auth type: ' + auth) self.auth = auth self.https_only = conf.get('auth_https_only') if auth == 'basic': htpasswd = os.path.join(conf['data_dir'], 'htpasswd.db') htpasswd = conf.get('auth_htpasswd') or htpasswd self.htpasswd = HtpasswdFile(htpasswd) self._log('Using htpasswd: ' + str(htpasswd)) self.realm = conf.get('auth_realm', 'fileshelf') def _log(self, msg): print('## Auth: ' + msg) def check_access(self, handler): @wraps(handler) def decorated(*args, **kwargs): req = flask.request if self.https_only and req.environ['wsgi.url_scheme'] != 'https': raise AuthError('HTTPS required') path = req.environ['PATH_INFO'] user = None if self.auth is None: user = UserDb.DEFAULT elif self.auth == 'basic': user = self._check_basic_auth(req) if user is None: hdrs = { 'WWW-Authenticate': 'Basic realm="%s"' % self.realm } # TODO: a nicer page return flask.Response('Login Required', 401, hdrs) else: raise AuthError('unknown auth type: ' + self.auth) path = path.encode('latin1').decode('utf8') self._log('%s %s://%s@%s%s?%s' % (req.method, req.environ['wsgi.url_scheme'], user, req.environ['HTTP_HOST'], path, req.environ['QUERY_STRING'])) flask.request.user = user return handler(*args, **kwargs) return decorated def _check_basic_auth(self, req): auth = req.headers.get('Authorization') if not auth: self._log('basic auth: no Authorization') return None if not auth.startswith('Basic '): self._log('basic auth: not Basic') return None auth = auth.split()[1] auth = auth.encode('ascii') user, passwd = b64decode(auth).split(b':') ret = self.htpasswd.check_password(user, passwd) user = user.decode('ascii') passwd = passwd.decode('ascii') if ret is None: self._log('basic auth: user %s not found' % user) return None if ret is False: self._log('basic auth: check_password(<%s>, <%s>) failed' % (user, passwd)) return None return user def user_exists(self, user): return (user in self.htpasswd)
class HtPasswdAuth: """Configure htpasswd based basic and token authentication.""" def __init__(self, app=None): """Boiler plate extension init with log_level being declared""" self.users = HtpasswdFile() self.app = app if app is not None: self.init_app(app) def init_app(self, app): """ Find and configure the user database from specified file """ # pylint: disable=inconsistent-return-statements app.config.setdefault('FLASK_AUTH_ALL', False) app.config.setdefault('FLASK_AUTH_REALM', 'Login Required') # Default set to bad file to trigger IOError app.config.setdefault('FLASK_HTPASSWD_PATH', '/^^^/^^^') # Load up user database try: self.load_users(app) except IOError: log.critical('No htpasswd file loaded, please set `FLASK_HTPASSWD`' 'or `FLASK_HTPASSWD_PATH` environment variable to a ' 'valid apache htpasswd file.') # Allow requiring auth for entire app, with pre request method @app.before_request def require_auth(): # pylint: disable=unused-variable """Pre request processing for enabling full app authentication.""" if not current_app.config['FLASK_AUTH_ALL']: return None is_valid, user = self.authenticate() if not is_valid: return self.auth_failed() g.user = user def load_users(self, app): """ Load users from configured file. Args: app (flask.Flask): Flask application to load users from. Raises: IOError: If the configured htpasswd file does not exist. Returns: None """ self.users = HtpasswdFile(app.config['FLASK_HTPASSWD_PATH']) def check_basic_auth(self, username, password): """ This function is called to check if a username / password combination is valid via the htpasswd file. """ valid = self.users.check_password(username, password) if not valid: log.warning('Invalid login from %s', username) valid = False return (valid, username) @staticmethod def get_signature(): """ Setup crypto sig. """ return Serializer(current_app.config['FLASK_SECRET']) def get_hashhash(self, username): """ Generate a digest of the htpasswd hash """ return hashlib.sha256(self.users.get_hash(username)).hexdigest() def generate_token(self, username): """ assumes user exists in htpasswd file. Return the token for the given user by signing a token of the username and a hash of the htpasswd string. """ serializer = self.get_signature() return serializer.dumps({ 'username': username, 'hashhash': self.get_hashhash(username) }).decode('UTF-8') def check_token_auth(self, token): """ Check to see who this is and if their token gets them into the system. """ serializer = self.get_signature() try: data = serializer.loads(token) except BadSignature: log.warning('Received bad token signature') return False, None if data['username'] not in self.users.users(): log.warning('Token auth signed message, but invalid user %s', data['username']) return False, None if data['hashhash'] != self.get_hashhash(data['username']): log.warning( 'Token and password do not match, %s ' 'needs to regenerate token', data['username']) return False, None return True, data['username'] @staticmethod def auth_failed(): """ Sends a 401 response that enables basic auth """ if request.endpoint == "auth": r = make_response() r.status_code = 401 r.headers.set( 'WWW-Authenticate', 'basic realm="{0}"'.format( current_app.config['FLASK_AUTH_REALM'])) return r else: return abort(401) def authenticate(self): """Authenticate user by any means and return either true or false. Args: Returns: tuple (is_valid, username): True is valid user, False if not """ basic_auth = request.authorization is_valid = False user = None if basic_auth: is_valid, user = self.check_basic_auth(basic_auth.username, basic_auth.password) else: # Try token auth token = request.headers.get('Authorization', None) param_token = request.args.get('access_token') if token or param_token: if token: # slice the 'token ' piece of the header (following # github style): token = token[6:] else: # Grab it from query dict instead token = param_token log.debug('Received token: %s', token) is_valid, user = self.check_token_auth(token) return (is_valid, user) def required(self, func): """ Decorator function with basic and token authentication handler """ @wraps(func) def decorated(*args, **kwargs): """ Actual wrapper to run the auth checks. """ is_valid, user = self.authenticate() if not is_valid: return self.auth_failed() kwargs['user'] = user return func(*args, **kwargs) return decorated
def check_auth(username, password): '''This function is called to check if a username / password combination is valid.''' # log.info('check_auth {} {}'.format(username, password)) ht = HtpasswdFile("user.htpasswd") return ht.check_password(username, password)
def staff_check_user_password_htpasswd(username, password): cwd = os.path.abspath(__file__)[:-8] ht = HtpasswdFile(cwd + "login/.staff.htpasswd") return ht.check_password(username, password)
class HtPasswdAuth(object): """Configure htpasswd based basic and token authentication.""" def __init__(self, app=None): """Boiler plate extension init with log_level being declared""" self.users = HtpasswdFile() self.app = app if app is not None: self.init_app(app) def init_app(self, app): """ Find and configure the user database from specified file """ app.config.setdefault('FLASK_AUTH_ALL', False) app.config.setdefault('FLASK_AUTH_REALM', 'Login Required') # Default set to bad file to trigger IOError app.config.setdefault('FLASK_HTPASSWD_PATH', '/^^^/^^^') # Load up user database try: self.load_users(app) except IOError: log.critical( 'No htpasswd file loaded, please set `FLASK_HTPASSWD`' 'or `FLASK_HTPASSWD_PATH` environment variable to a ' 'valid apache htpasswd file.' ) # Allow requiring auth for entire app, with pre request method @app.before_request def require_auth(): # pylint: disable=unused-variable """Pre request processing for enabling full app authentication.""" if not current_app.config['FLASK_AUTH_ALL']: return is_valid, user = self.authenticate() if not is_valid: return self.auth_failed() g.user = user def load_users(self, app): """ Load users from configured file. Args: app (flask.Flask): Flask application to load users from. Raises: IOError: If the configured htpasswd file does not exist. Returns: None """ self.users = HtpasswdFile( app.config['FLASK_HTPASSWD_PATH'] ) def check_basic_auth(self, username, password): """ This function is called to check if a username / password combination is valid via the htpasswd file. """ valid = self.users.check_password( username, password ) if not valid: log.warning('Invalid login from %s', username) valid = False return ( valid, username ) @staticmethod def get_signature(): """ Setup crypto sig. """ return Serializer(current_app.config['FLASK_SECRET']) def get_hashhash(self, username): """ Generate a digest of the htpasswd hash """ return hashlib.sha256( self.users.get_hash(username) ).hexdigest() def generate_token(self, username): """ assumes user exists in htpasswd file. Return the token for the given user by signing a token of the username and a hash of the htpasswd string. """ serializer = self.get_signature() return serializer.dumps( { 'username': username, 'hashhash': self.get_hashhash(username) } ).decode('UTF-8') def check_token_auth(self, token): """ Check to see who this is and if their token gets them into the system. """ serializer = self.get_signature() try: data = serializer.loads(token) except BadSignature: log.warning('Received bad token signature') return False, None if data['username'] not in self.users.users(): log.warning( 'Token auth signed message, but invalid user %s', data['username'] ) return False, None if data['hashhash'] != self.get_hashhash(data['username']): log.warning( 'Token and password do not match, %s ' 'needs to regenerate token', data['username'] ) return False, None return True, data['username'] @staticmethod def auth_failed(): """ Sends a 401 response that enables basic auth """ return Response( 'Could not verify your access level for that URL.\n' 'You have to login with proper credentials', 401, {'WWW-Authenticate': 'Basic realm="{0}"'.format( current_app.config['FLASK_AUTH_REALM'] )} ) def authenticate(self): """Authenticate user by any means and return either true or false. Args: Returns: tuple (is_valid, username): True is valid user, False if not """ basic_auth = request.authorization is_valid = False user = None if basic_auth: is_valid, user = self.check_basic_auth( basic_auth.username, basic_auth.password ) else: # Try token auth token = request.headers.get('Authorization', None) param_token = request.args.get('access_token') if token or param_token: if token: # slice the 'token ' piece of the header (following # github style): token = token[6:] else: # Grab it from query dict instead token = param_token log.debug('Received token: %s', token) is_valid, user = self.check_token_auth(token) return (is_valid, user) def required(self, func): """ Decorator function with basic and token authentication handler """ @wraps(func) def decorated(*args, **kwargs): """ Actual wrapper to run the auth checks. """ is_valid, user = self.authenticate() if not is_valid: return self.auth_failed() kwargs['user'] = user return func(*args, **kwargs) return decorated
def is_valid_user(email, password): cwd = os.path.abspath(__file__)[:-7] ht = HtpasswdFile(cwd + ".htpasswd") return ht.check_password(email, password)