from enum import Enum from flask_principal import Identity, identity_changed from app import app from auth.auth_context import (set_authenticated_user, set_validated_token, set_grant_context, set_validated_oauth_token) from auth.scopes import scopes_from_scope_string from auth.permissions import QuayDeferredPermissionUser class AuthKind(Enum): cookie = 'cookie' basic = 'basic' oauth = 'oauth' signed_grant = 'signed_grant' credentials = 'credentials' class ValidateResult(object): """ A result of validating auth in one form or another. """ def __init__(self, kind, missing=False, user=None, token=None, oauthtoken=None, robot=None, signed_data=None, error_message=None): self.kind = kind self.missing = missing self.user = user self.robot = robot self.token = token self.oauthtoken = oauthtoken self.signed_data = signed_data self.error_message = error_message def tuple(self): return (self.kind, self.missing, self.user, self.token, self.oauthtoken, self.robot, self.signed_data, self.error_message) def __eq__(self, other): return self.tuple() == other.tuple() def apply_to_context(self): """ Applies this auth result to the auth context and Flask-Principal. """ # Set the various pieces of the auth context. if self.oauthtoken: set_authenticated_user(self.authed_user) set_validated_oauth_token(self.oauthtoken) elif self.authed_user: set_authenticated_user(self.authed_user) elif self.token: set_validated_token(self.token) elif self.signed_data: if self.signed_data['user_context']: set_grant_context({ 'user': self.signed_data['user_context'], 'kind': 'user', }) # Set the identity for Flask-Principal. if self.identity: identity_changed.send(app, identity=self.identity) def with_kind(self, kind): """ Returns a copy of this result, but with the kind replaced. """ return ValidateResult(kind, self.missing, self.user, self.token, self.oauthtoken, self.robot, self.signed_data, self.error_message) @property def authed_user(self): """ Returns the authenticated user, whether directly, or via an OAuth token. """ if not self.auth_valid: return None if self.oauthtoken: return self.oauthtoken.authorized_user return self.user if self.user else self.robot @property def identity(self): """ Returns the identity for the auth result. """ if not self.auth_valid: return None if self.oauthtoken: scope_set = scopes_from_scope_string(self.oauthtoken.scope) return QuayDeferredPermissionUser.for_user(self.oauthtoken.authorized_user, scope_set) if self.authed_user: return QuayDeferredPermissionUser.for_user(self.authed_user) if self.token: return Identity(self.token.code, 'token') if self.signed_data: identity = Identity(None, 'signed_grant') identity.provides.update(self.signed_data['grants']) return identity return None @property def has_user(self): """ Returns whether a user (not a robot) was authenticated successfully. """ return bool(self.user) @property def auth_valid(self): """ Returns whether authentication successfully occurred. """ return self.user or self.token or self.oauthtoken or self.robot or self.signed_data