The security infrastructure in Morepath helps you make sure that web
resources published by your application are only accessible by those
persons that are allowed to do so. If a person is not allowed access,
they will get an appropriate HTTP error: HTTP Forbidden 403.

The function decorated by the @App.identity_policy decorator takes
an optional settings argument, which provides access to the App settings.
So if you define some settings for the identity policy you can pass them
in like this:

The identity policy only establishes who someone is claimed to
be. It doesn’t verify whether that person is actually who they say
they are. For identity policies where the browser repeatedly sends the
username/password combination to the server, such as with basic
authentication, implemented by more.basicauth and cookie-based
authentication like more.itsdangerous, we need to check each
time whether the claimed identity is actually a real identity.

The identity object received here is as established by the
identity policy. What the attributes of the identity object are
(besides username) is also determined by the specific identity
policy you install.

Note that user_has_password stands in for whatever method you use
to check a user’s password; it’s not part of Morepath.

If you use an identity policy based on the session (which you’ve made
secure otherwise), or on a cryptographic token based authentication
system such as the one implemented by more.jwtauth, the claimed
identity is actually enough.

We know that the claimed identity is actually the one given to the
user earlier when they logged in. No database-based identity check is
required to establish that this is a legitimate identity. You can
therefore implement verify_identity like this:

@App.verify_identity()defverify_identity(identity):# trust the identity established by the identity policyreturnTrue

So now we know how identity gets established, and how it can be
verified. We haven’t discussed yet how a user actually logs in to
establish an identity in the first place.

For this, we need two things:

Some kind of login form. Could be taken care of by client-side code
or by a server-side view. We leave this as an exercise for the
reader.

The view that the login data is submitted to when the user tries to
log in.

How this works in detail is up to your application. What’s common to
login systems is the action we take when the user logs in, and the
action we take when the user logs out. When the user logs in we need to
remember their identity on the response, and when the user logs out
we need to forget their identity again.

Here is a sketch of how logging in works. Imagine we’re in a Morepath
view where we’ve already retrieved username and password from
the request (coming from a login form):

# check whether user has password, using password hash and databaseifnotuser_has_password(username,password):return"Sorry, login failed"# or something more fancy# now that we've established the user, remember it on the response@request.afterdefremember(response):identity=morepath.Identity(username)request.app.remember_identity(response,request,identity)

This is enough for session-based or cryptographic token-based
authentication.

For cookie-based authentication where the password is sent as a cookie
to the server for each request, we need to make sure to include the
password the user used to log in, so that remember can then place
it in the cookie so that it can be sent back to the server:

Now that we have a way to establish identity and a way for the user to
log in, we can move on to permissions. Permissions are per view. You
can define rules for your application that determine when a user has a
permission.

Let’s say we want two permissions in our application, view and
edit. We define those as plain Python classes:

classViewPermission(object):passclassEditPermission(object):pass

Permission Hierarchy

Since permissions are classes they could inherit from each other and
form some kind of permission hierarchy, but we’ll keep things simple
here. Often a flat permission hierarchy is just fine.

Now we can protect views with those permissions. Let’s say we have a
Document model that we can view and edit:

Now that we give people a claimed identity and we have guarded our
views with permissions, we need to establish who has what permissions
where using some rules. We can use the
morepath.App.permission_rule() directive to do that.

This is just is one hypothetical rule. allowed_users on
Document objects is totally made up and not part of Morepath. Your
application can have any rule at all, using any data, to determine
whether someone has a permission.

What if we don’t want to have to define permissions on a per-model
basis? In our application, we may have a generic way to check for
the edit permission on any kind of model. We can easily do that too,
as Morepath knows about inheritance: