Hello, Chris.

On Monday October 27, 2008 12:54:13 Chris McDonough wrote:
> I'd like to understand this a little better.
> In the authorization stuff in repoze.bfg I have a "repoze.who security
> policy" that assumes a couple of things:
> - A "security policy" checks object "acls" against "principal" info (group
> and user names).
> - People make declarations about their views, protecting each with a
> permission. An acl makes an assertion about which users or groups
> ("principals") possess which permission against some model object.
> - a sequence of group identifiers will be passed in the identity using a
> r.who metadata provider that puts stuff into identity['groups'].  The
> combination of identity['repoze.who.userid'] and identity['groups'] forms
> the list of principals checked by any found acl.

tgext.authorization works in a similar way (see below).

> There is no other tie between the authentication framework (the security
> policy) and repoze.who.  The documentation for the security policy lives in
> repoze.bfg. There is also a RemoteUserSecurityPolicy which does not require
> repoze.who; instead it just relies on environ['REMOTE_USER'] as its sole
> principal; everything else works the same.

In the case of tgext.authorization, it has one repoze.who metadata provider 
that loads into the identity dict the groups to which the authenticated user 
belongs and the permissions granted to such groups.

This metadata provider plugin (called "AuthorizationMetadata") may get the 
groups and permissions from many sources (databases, ini files, etc).

Roughly, this is how it works:
  1.- If the user has been authenticated, repoze.who runs the 
AuthorizationMetadata plugin to load the groups and permissions.
  2.- This week I hope to finish support for anonymous (non authenticated) 
users, using an IAuthenticator plugin which loads such groups and permissions 
for anonymous users (since a metadata provider would not get called in this 
case). Of course, the "real" authenticators would have to be called before.
  3.- Then, developers use authorization assertions in their controllers.

And for what it's worth, the "glue" between repoze.who and tgext.authorization 
is its middleware module 
and the "glue" between TG2 and tgext.authorization is its "quickstart" module 

But I suggest you check the quick introduction to authentication and 
authorization in TG2 and then the docs for tgext.authorization, which are 
included in the documentation for TG2; I'm sure you'll get a better overview 
reading this documentation. However, the online version is not up-to-date yet, 
so it's temporarily available on my site:

> For each of my customer projects that uses both bfg and repoze.who, I've
> found it necessary to create one new metadata plugin to get the group
> information from wherever it lives.  But I've not considered putting these
> back into repoze.who or starting a project for them, because they are
> typically very simple (on the order of maybe 10 lines of code each).  OTOH,
> they are always slightly different from each other, because customers have
> weird requirements.

In tgext.authorization you have the following components:
 * A "source" is where your groups and/or your permissions are stored. It may 
be a "group source" or a "permission source".
 * A "group source" is a source that stores groups (Htgroups file, a database, 
ini file, etc).
 * A "permission source" is a source that stores permissions (a database, ini 
file, etc).
 * A "source adapter" is a tgext.authorization class that handles a given type 
of source.

So, you only need one metadata provider that "knows" how to find the groups 
and permissions from different sources. For example, you could use the code 
    from repoze.who.plugins.htpasswd import HTPasswdPlugin, crypt_check
    from tgext.authorization.middleware import setup_auth
    # Please note that the plugins below have not been created yet; want to
    # jump in?
    from tgext.authorization.plugins.htgroups import HtgroupsAdapter
    from tgext.authorization.plugins.ini import IniPermissionAdapter

    # Defining the group adapters; you may add as much as you need:
    groups = {'all_groups': HtgroupsAdapter('/path/to/groups.htgroups')}

    # Defining the permission adapters; you may add as much as you need:
    permissions = {'all_perms': IniPermissionAdapter('/path/to/perms.ini')}

    # repoze.who authenticators; you may add as much as you need:
    htpasswd_auth = HTPasswdPlugin('/path/to/users.htpasswd', crypt_check)
    authenticators = [('htpasswd', htpasswd_auth)]

    app_with_auth = setup_auth(

Where setup_auth() is the function that configures repoze.who by loading 
tgext.authorization's AuthorizationMetadata.

And you also get a bonus: The ability to manage your groups and permissions 
under a source-independent API, either from your application or from an 
external program.

> Are these plugins the bits of code that you believe we should consolidate
> into a package?

Not exactly. 

For example, if I'm developing a WSGI application that uses r.who and 
tgext.authorization, and I store my users' data, groups and permissions in a 
database... I would have to configure repoze.who's SQL authenticator and 
tgext.authorization's SQL groups and permissions "fetchers", separately, while 
they share some configuration bits.

The approach I'm taking with tgext.authorization, which is out of the scope of 
authorization itself, is to make it also setup authentication via repoze.who 
so that others won't have to repeat auth settings. See, for example, the 
function that configures authentication and authorization in the situation 
described above (users' credentials, groups and permissions stored in a 
database), called setup_sql_auth():

The same would happen if I want to use LDAP authentication and re-user my 
LDAP's Organizational Units as groups in my application.

> > I propose to keep developing the authentication framework independently,
> > but merge both documentations and both plugin namespaces. Specifically, I
> > have two options in mind:
> >   1.- Turn tgext.authorization into repoze.what ("who" -> authentication;
> > "what" -> authorization). But this won't solve the problem with the
> > documentation nor the plugins.
> That'd be fine by me.

Great, then if we don't go for a new project based on r.who and 
tgext.authorization, that would be great for the later.

> >   2.- Start a new project under a new namespace (possibly under
> > repoze.*?), made up of the modules {project}.authentication (former
> > repoze.who), {project}.authorization (former tgext.authorization),
> > {project}.plugins as a namespace for plugins (plugins may add
> > {project}.authentication's identifiers, authenticators, challengers
> > and/or metadata providers, as well as {project}.authorization's group
> > and/or permission source adapters) and another module that will act as
> > the "glue" to enable authorization. Also, both documentations would be
> > merged.
> To be honest, I'd like to keep authentication and authorization (at least
> nontrivial-policy-based authorization) in separate packages in order to
> avoid the fate of AuthKit, which tries to do both, and fails.  I think it's
> a bit too much of a mental jump for some people to understand the
> difference between the two without someone spelling it out for them, and
> package separation tends to do that.

I agree, but my idea is to have repoze.who part of main "WSGI Auth*" project, 
where it could also be used independently of the authorization framework, 
while the authorization framework does fully depends on the authentication 

> That said, the idea of having a package (ala repoze.what) that contains who
> metadata providers that provide group info along with authorization
> decorators that actually use that info sounds fine to me.  I may not use
> the decorators myself, but I could contribute my little snippets of
> group-metadata-provider plugins to repoze.what were we to descend on some
> defacto standard about how those plugins should put that info into the
> repoze.who identity.
> Let's take a case at hand... In your LDAP scenario, you've written the LDAP
> who plugin, now you need to choose where to put an LDAP groups metadata
> plugin.  It *could* go into the LDAP plugin itself.  Or it could go in some
> separate package like repoze.what.  In the case of LDAP it *might* be best
> to put the metadata provider plugin into the LDAP plugin itself, because
> causing e.g. repoze.what to require python-ldap might be painful due to its
> requirement that it wants to compile against openldap libs. In fact, now 
> that I wrote that, I can't think of a reason, for any plugin
> of significant dependenty complexity, why the metadata plugin shouldn't
> exist in the package that provides all the other plugins. Maybe we just
> need to establish a loose standard for metadata provision.  We'd then put
> the authentication stuff in some other package, and have the authenticators
> *use* that standard, but each metadata provider which provides it would
> still live in its respective who plugin package?

The problem is that we couldn't use an LDAP metadata provider to retrieve 
Organizational Units as groups, but a tgext.authorization's (or repoze.what's) 
so-called Group Source Adapter (or Permission Source Adapter). Likewise, 
groups and permissions stored in databases are not loaded by SQL metadata 
providers, but by Group/Permission Source Adapters (which also enable you to 
manage your groups and permissions under a source-independent API).

Group/Permission source adapters don't deal with repoze.who, they're only used 
by tgext.authorization, so I'm not sure if including them in a repoze.who 
plugin would be accurate.

We could, among other things, unify repoze.who's and tgext.authorization's SQL 
plugins. The tgext.authorization SQL plugin provides the SQL group source 
adapter and the SQL permission source adapter:

What a long email! This is it, for the time being :)

Gustavo Narea.

Get rid of unethical constraints! Switch to Freedomware:

Repoze-dev mailing list

Reply via email to