# Copyright 2017 Canonical Ltd.
# Licensed under the LGPLv3, see LICENCE file for details.
import abc
from ._error import IdentityError
class Identity(object):
''' Holds identity information declared in a first party caveat added when
discharging a third party caveat.
'''
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def id(self):
''' Returns the id of the user.
May be an opaque blob with no human meaning. An id is only considered
to be unique with a given domain.
:return string
'''
raise NotImplementedError('id method must be defined in subclass')
@abc.abstractmethod
def domain(self):
'''Return the domain of the user.
This will be empty if the user was authenticated
directly with the identity provider.
:return string
'''
raise NotImplementedError('domain method must be defined in subclass')
class ACLIdentity(Identity):
''' ACLIdentity may be implemented by Identity implementations
to report group membership information.
'''
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def allow(self, ctx, acls):
''' reports whether the user should be allowed to access
any of the users or groups in the given acl list.
:param ctx(AuthContext) is the context of the authorization request.
:param acls array of string acl
:return boolean
'''
raise NotImplementedError('allow method must be defined in subclass')
class SimpleIdentity(ACLIdentity):
''' A simple form of identity where the user is represented by a string.
'''
def __init__(self, user):
self._identity = user
def domain(self):
''' A simple identity has no domain.
'''
return ''
def id(self):
'''Return the user name as the id.
'''
return self._identity
def allow(self, ctx, acls):
'''Allow access to any ACL members that was equal to the user name.
That is, some user u is considered a member of group u and no other.
'''
for acl in acls:
if self._identity == acl:
return True
return False
class IdentityClient(object):
''' Represents an abstract identity manager. User identities can be based
on local informaton (for example HTTP basic auth) or by reference to an
external trusted third party (an identity manager).
'''
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def identity_from_context(self, ctx):
''' Returns the identity based on information in the context.
If it cannot determine the identity based on the context, then it
should return a set of caveats containing a third party caveat that,
when discharged, can be used to obtain the identity with
declared_identity.
It should only raise an error if it cannot check the identity
(for example because of a database access error) - it's
OK to return all zero values when there's
no identity found and no third party to address caveats to.
@param ctx an AuthContext
:return: an Identity and array of caveats
'''
raise NotImplementedError('identity_from_context method must be '
'defined in subclass')
@abc.abstractmethod
def declared_identity(self, ctx, declared):
'''Parses the identity declaration from the given declared attributes.
TODO take the set of first party caveat conditions instead?
@param ctx (AuthContext)
@param declared (dict of string/string)
:return: an Identity
'''
raise NotImplementedError('declared_identity method must be '
'defined in subclass')
class NoIdentities(IdentityClient):
''' Defines the null identity provider - it never returns any identities.
'''
def identity_from_context(self, ctx):
return None, None
def declared_identity(self, ctx, declared):
raise IdentityError('no identity declared or possible')