score.auth¶
This module provides authentication (“who are you?”) and authorization (“are
you allowed to do this?”) for your application. The former is implemented with
the use of so-called Authenticators
, the latter with
a clever workflow for defining and probing rules.
Quickstart¶
Authentication¶
Add this module to your initialization list and configure it to make use of the
score.session
module (assuming you have a User
class in your
database):
[score.init]
modules =
score.db
score.session
score.auth
[auth]
authenticators =
score.auth.authenticator.SessionAuthenticator(path.to.User)
You can now store assign a User
to your context
and the authenticator will store and retrieve that user from your session in
subsequent contexts:
>>> with score.ctx.Context() as ctx:
... assert ctx.actor is None
... ctx.actor = ctx.db.query(path.to.User).first()
...
>>> with score.ctx.Context() as ctx:
... assert ctx.actor is ctx.db.query(path.to.User).first()
...
Authorization¶
Create a rule set for authorization queries and add some rules:
ruleset = score.auth.RuleSet()
@ruleset.rule('confuse', Cat)
def confuse(ctx, cat):
# decide, whether this cat may be confused given this context
return isinstance(ctx.actor, Vet)
The module configuration should point to the given rule set for authorization:
[auth]
authenticators =
score.auth.authenticator.SessionAuthenticator(path.to.User)
ruleset = path.to.ruleset
You can now query your context for permissions:
>>> ctx.permits('confuse', cat)
False
Configuration¶
-
score.auth.
init
(confdict, ctx)[source]¶ Initializes this module acoording to our module initialization guidelines with the following configuration keys:
- ruleset RuleSet()
- A dotted path to an instance of
RuleSet
in your project. This module will be initialized without any rules, if this configuration key is omitted, resulting in denial of every operation. - authenticators list()
- List of
Authenticators
capable of determining the current actor. - ctx.member actor
The context member under which the current actor should be made available. Leaving this at its default will allow you to access the current actor as the following:
>>> ctx.actor
Details¶
Authenticators¶
When the configured module is requested to determine the currently active
user, it will need to forward the request to registered Authenticators
. These Authenticators are organized as a chain, each Authenticator asking the next one if it cannot
figure out the current user.
A typical chain of Authenticators could look like the following:
- A login authenticator: Tests, if a form was submitted, that would log the user in. If it was not, it asks the next Authenticator.
SessionAuthenticator
: Checks the session, if there is a previously stored user. Continues asking the next Authenticator if there is not.NullAuthenticator
: Returns None to indicate that the chain has reached its end.
An example login authenticator could look like the following:
from score.auth import Authenticator
class LoginAuthenticator(Authenticator):
def retrieve(self, ctx):
user = self._perform_login(ctx)
if user:
return user
else:
# the login was not successful, ask the next authenticator to
# retrieve the current user.
return self.next.retrieve(ctx)
def _perform_login(self, ctx):
if not hasattr(ctx, 'http'):
return None
if 'username' not in ctx.http.request.POST:
return None
if 'password' not in ctx.http.request.POST:
return None
username = ctx.http.request.POST['username']
user = ctx.db.query(db.User).\
filter(db.User.username == username)
first()
if not user:
return None
if not user.verify_password(ctx.http.request.POST['password']):
return None
# we have a logged in user, so pass it to all subsequent
# authenticators to allow them storing the value.
self.next.store(ctx, user)
return user
RuleSets¶
The RuleSet
is a decorator for defining rules. A rule
consists of an operation and any number of type objects, like the following:
ruleset = score.auth.RuleSet()
@ruleset.rule('sing', Song)
def sing(ctx, song):
return song.performer == ctx.actor and \
Permission.SING_A_SONG in actor.permissions
Whenever the context is queried whether it is possible to sing a specific Song, this function will be invoked to provide the answer:
if ctx.permits('sing', Song.load('Galaxy Song')):
# this must be Stephen Hawking!
It is also possible to omit the parameters to the decorator, if the rule does not require any objects. The name of the rule will be the name of the function in this case:
ruleset = score.auth.RuleSet()
@ruleset.rule # NOTE: no definitions here ..
def sing(ctx): # .. and no additional function parameters
pass
API¶
-
score.auth.
init
(confdict, ctx)[source] Initializes this module acoording to our module initialization guidelines with the following configuration keys:
- ruleset RuleSet()
- A dotted path to an instance of
RuleSet
in your project. This module will be initialized without any rules, if this configuration key is omitted, resulting in denial of every operation. - authenticators list()
- List of
Authenticators
capable of determining the current actor. - ctx.member actor
The context member under which the current actor should be made available. Leaving this at its default will allow you to access the current actor as the following:
>>> ctx.actor
-
class
score.auth.
ConfiguredAuthModule
(ruleset, ctx_member)[source]¶ This module’s
configuration class
.-
permits
(ctx, operation, *args, raise_=False)[source]¶ A proxy for
RuleSet.permits()
of the configuredruleset
instance.
-
-
class
score.auth.
RuleSet
[source]¶ Stores rules and handles operations for classes.
-
permits
(ctx, operation, *args, raise_=False)[source]¶ Checks if given operation is allowed on given args in given context.
-
rule
(operation, *args)[source]¶ Decorator for adding a rule to this RuleSet.
The function can be used in two different ways: Either it directly annotates a function …
@ruleset.rule def sing(ctx): return ctx.actor.name == 'Stephen Hawking'
… or it defines an operation and a list of argument types, which must match the types of the arguments of the call to
RuleSet.permits()
:@ruleset.rule('rewrite', Song) def rewrite_song(ctx, song): return True # songs may be rewritten at any time
-
-
class
score.auth.authenticator.
Authenticator
(conf, next)[source]¶ An object that can query (and possibly remember) the currently acting user.
-
class
score.auth.authenticator.
NullAuthenticator
[source]¶ Always returns None as the current user. This class is used as the last
Authenticator
in an authentication chain.
-
class
score.auth.authenticator.
SessionAuthenticator
(conf, next, actor_class=None, session_key='actor')[source]¶ Makes a lookup in the current session context member.