No peak.security for 0.9

0 views
Skip to first unread message

Kevin Dangoor

unread,
Jan 20, 2006, 9:58:58 PM1/20/06
to turbo...@googlegroups.com
I've been thinking about combining Identity + peak.security (or, more
specifically, RuleDispatch) for the past couple of weeks. (Not
constantly, mind you... just when I've had the chance.) Computer
science is all about tradeoffs. Occasionally, you'll have something
that is distinctly a win with no drawbacks. More often than not,
though, you need to balance things out between flexibility, complexity
and performance. But you knew that, already.

In this particular case, I think that the Identity user API is really
easy to use and will meet a good variety of needs (but certainly not
all). peak.security is the kind of thing that can meet everyone's
needs, but wouldn't be as easy for some of the common cases that
Identity is good at.

Here's my thinking:

1) Leave the Identity user API as is for 0.9.0
2) Don't try to work the notion of a "subject" into the existing API.
The idea with a "subject" is: does this user have "edit" permission
*for this item*. It's very app specific, and RuleDispatch would be a
big win here.
3) Integrate peak.security/RuleDispatch into some later release
4) Ensure that there are enough plugpoints that people can take
advantage of as much Identity code as possible.

Other people here have used Identity far more than I have. How has it
been as far as the API for you? (Particularly since Jeff created his
predicate system.)

Kevin

--
Kevin Dangoor
Author of the Zesty News RSS newsreader

email: k...@blazingthings.com
company: http://www.BlazingThings.com
blog: http://www.BlueSkyOnMars.com

Simon Belak

unread,
Jan 21, 2006, 6:03:06 AM1/21/06
to turbo...@googlegroups.com
Can I just sneak some generic functions into Identity than? ;)

What I would like is to have more flexibility when it comes to
authentication failure. Therefore I propose adding function fail()
defined as:

@generic()
def fail(func, errors=None):
pass

@fail.when(strategy.default)
def _default_redirect(func, errors):
raise cherrypy.InternalRedirect(
current_provider.url_for_identity_failure())

Predominantly it would get called from require(), but of curse it could
be triggered manually as well.

Motivation:

1) Contextual redirection

2) Additional logging
For example one may want to log every failed attempt to log-in as an
administrator.

3) Additional error handling
For example properly ending a transaction, saving input of a multi-page
form, etc.

This enchantment is fully backwards compatible and imposes no overhead
to those who do not wish to use it.

Cheers,
Simon


--
Simon Belak
vodja projektnih skupin

e: simon...@hruska.si
---------------------------------------------------------------------
Hruska d.o.o., agencija za nove medije
Ilirska 21, SI-1000 Ljubljana

t: +386 1 430 25 86 f: +386 1 430 25 87

s: http://www.hruska.si
s: http://akademija.hruska.si (izobrazevalni portal)
s: http://www.elor.si (kadrovski sistem letnih razgovorov)
------------------------------------------------------------------------
Hruska.si - socne resitve


To elektronsko sporocilo in vse morebitne priloge so poslovna skrivnost
in namenjene izkljucno naslovniku. Ce ste sporocilo prejeli pomotoma,
Vas prosimo, da obvestite posiljatelja, sporocilo pa takoj unicite.
Kakrsnokoli razkritje, distribucija ali kopiranje vsebine sporocila je
strogo prepovedano.

This e-mail and any attachments may contain confidential and/or
privileged information and is intended solely for the addressee. If you
are not the intended recipient (or have received this e-mail in error)
please notify the sender immediately and destroy this e-mail. Any
unauthorized copying, disclosure or distribution of the material in
this e-mail, or any action taken or omitted to be taken in reliance on
it, is strictly prohibited.

Jeff Watkins

unread,
Jan 21, 2006, 10:09:29 AM1/21/06
to turbo...@googlegroups.com
On 21 Jan, 2006, at 6:03 am, Simon Belak wrote:

Can I just sneak some generic functions into Identity than? ;)

I have no problem with adding generic functions to Identity if generic functions solve a problem that can't be solved any other way.


What I would like is to have more flexibility when it comes to authentication failure. Therefore I propose adding function fail() defined as:

@generic()
def fail(func, errors=None):
pass

@fail.when(strategy.default)
def _default_redirect(func, errors):
raise cherrypy.InternalRedirect(
current_provider.url_for_identity_failure())

Predominantly it would get called from require(), but of curse it could be triggered manually as well.

There's no need to call this from the require decorator. It doesn't need any more flexibility than it already has. I don't find myself saying: "Gosh, I wish I could do XYZ in the require decorator, but I have no idea how without a generic failure function."

Motivation:

1) Contextual redirection

Try raising turbogears.redirect instead. That's what it's for, I think. Or if you need to redirect based on a specific set of errors, you should try specifying a callable for your identity-failure-url (soon to be committed).

2) Additional logging
For example one may want to log every failed attempt to log-in as an administrator.

I've been remiss about not adding enough logging to the Identity and Visit Tracking code. No admittedly, the standard logging might not be what everyone is looking for; I can envision Identity expanding to provide hooks for detailed authorisation logging.

3) Additional error handling
For example properly ending a transaction, saving input of a multi-page form, etc.

This is a general issue which shouldn't be solved in the Identity or Visit Tracking framework. Why would you have an authorisation failure in the MIDDLE of a multi-page form? This sounds more like a programmer-didn't-think-things-through-completely problem than anything with Identity.

This enchantment is fully backwards compatible and imposes no overhead to those who do not wish to use it.

So far no one has "stood up" and said: "I need to be able to X and I just can't without generic functions." And my experience managing software projects leads me to shy away from features that don't solve a problem.

--

Jeff Watkins

http://newburyportion.com/


Democracy n: A country where the newspapers are pro-American.



Ksenia Marasanova

unread,
Jan 21, 2006, 10:43:10 AM1/21/06
to turbo...@googlegroups.com
2006/1/21, Kevin Dangoor <dan...@gmail.com>:

> Other people here have used Identity far more than I have. How has it
> been as far as the API for you? (Particularly since Jeff created his
> predicate system.)

Works great for me. The only thing that I found a little confusing was
that std.identity in a template is an alias to identity.current...

--
Ksenia

Simon Belak

unread,
Jan 21, 2006, 11:14:14 AM1/21/06
to turbo...@googlegroups.com
Jeff Watkins wrote:
> On 21 Jan, 2006, at 6:03 am, Simon Belak wrote:
>
>> Can I just sneak some generic functions into Identity than? ;)
>
> I have no problem with adding generic functions to Identity if generic
> functions solve a problem that can't be solved any other way.

"Any other way"? Isn't this a bit drastic? The way I see it these 5
lines of code allow for multiple features which you say you are going to
implement along with a whole class of other possibilities.


> There's no need to call this from the require decorator. It doesn't need
> any more flexibility than it already has. I don't find myself saying:
> "Gosh, I wish I could do XYZ in the require decorator, but I have no
> idea how without a generic failure function."

Well I do. I like to separate functionalities. Handling security within
the controller deludes and is more error-prone. Not to mention, it is
not optimal approach when spreading development among a team.
Again, it's not about the generic functions (my remark was, obviously
poor, attempt at a joke), if you have a better (in terms of flexibility
versus bloatware) solution, I will gladly use that.

>> 1) Contextual redirection
>
> Try raising turbogears.redirect instead. That's what it's for, I
> think.
> Or if you need to redirect based on a specific set of errors, you
> should
> try specifying a callable for your identity-failure-url (soon to be
> committed).

If I understand correctly, this requires checking for permissions
"manually" from within the controller (or some such)?

>> 3) Additional error handling
>> For example properly ending a transaction, saving input of a
>> multi-page form, etc.
>
> This is a general issue which shouldn't be solved in the Identity or
> Visit Tracking framework. Why would you have an authorisation failure in
> the MIDDLE of a multi-page form? This sounds more like a
> programmer-didn't-think-things-through-completely problem than anything
> with Identity.

Perhaps it is just a design mistake, but take trac for instance. On
every page you have a "login" link. Yes it's dumb to try to login in the
middle of something, especially if one forgot one's password, but such
things do happen, especially in intranet applications. Sure, the
programmer could hide all inappropriate buttons etc., but than again
wouldn't it be even more prudent to select a tool where he didn't have to?

> So far no one has "stood up" and said: "I need to be able to X and I
> just can't without generic functions." And my experience managing
> software projects leads me to shy away from features that don't solve a
> problem.


I am a bit confused. Didn't you just said that you will (or have)
implement 2 out of 3 of my feature requests? I am most certainly flatter
if it is just for me. ;)


Simon

reflog

unread,
Jan 21, 2006, 11:52:32 AM1/21/06
to TurboGears
Hi.
Dunno if this is this post related, but what's the best way to
implement the 'subject' strategy that you pointed out?
I have a situation where i have a permission 'can_admin' which allows
to edit a part of the site, but I want another limitation on it, like
'can_admin and user == page.owner'

Can it be done with current identity?

Eli

Jeff Watkins

unread,
Jan 21, 2006, 1:08:59 PM1/21/06
to turbo...@googlegroups.com
Partly. You would have to manually check whether the user (identity.current.user) is the same as page.owner and you can use the has_permission('can_admin') predicate. But this wouldn't plug in very nicely into a require decorator.

So in your controller method you could place:

if has_permission('can_admin') and identity.current.user==page.owner:
do something
else:
do something else

The reason this won't plug into the decorator is I don't know *before* the method executes what the value of page is (or even that there *will* be a page variable). So I can't check its owner. Plus there's no project agnostic way of specifying ownership.

"Computers are like Old Testament gods; lots of rules and no mercy."

-- Joseph Campbell



reflog

unread,
Jan 22, 2006, 2:55:36 AM1/22/06
to TurboGears
Yep, i feared so :)
Thanks, Jeff.

Phillip J. Eby

unread,
Jan 22, 2006, 2:55:48 PM1/22/06
to TurboGears
Kevin Dangoor wrote:
>
> In this particular case, I think that the Identity user API is really
> easy to use and will meet a good variety of needs (but certainly not
> all). peak.security is the kind of thing that can meet everyone's
> needs, but wouldn't be as easy for some of the common cases that
> Identity is good at.

Which is why RuleDispatch offers programmatic APIs for dynamically
defining methods, so you can hide the details. Just because you *can*
give unlimited flexibility, doesn't mean you can't have an easy API.
For example, consider this command-line options framework:

http://peak.telecommunity.com/DevCenter/OptionsHowTo

Nowhere is there any mention of generic functions or adding methods or
criteria, but it internally uses a Dispatcher object that does lookups
based on class and attribute names. So, it's not necessary to expose
generic functions' complexity directly, if all you want to do is define
some type of registry of rules based on standardized access patterns.
RuleDispatch was created in part because I got tired of having to write
new kinds of registry classes all the time for PEAK, every time there I
had some new way of looking things up. RuleDispatch lets me focus on
the app and not on the data structures needed to implement it.

As a practical matter, however, RuleDispatch's more advanced APIs are
still alpha, which is to say they're likely to change significantly in
the future as I refactor to allow new features and improve the current
speed/space tradeoffs. With the limited time I have to work on it, I'm
not sure how long it will be before any of these things can get done.

Kevin Dangoor

unread,
Jan 23, 2006, 5:09:45 PM1/23/06
to turbo...@googlegroups.com
On 1/21/06, Simon Belak <simon...@hruska.si> wrote:
>
> Can I just sneak some generic functions into Identity than? ;)
>
> What I would like is to have more flexibility when it comes to
> authentication failure. Therefore I propose adding function fail()
> defined as:
>
> @generic()
> def fail(func, errors=None):
> pass
>
> @fail.when(strategy.default)
> def _default_redirect(func, errors):
> raise cherrypy.InternalRedirect(
> current_provider.url_for_identity_failure())
>
> Predominantly it would get called from require(), but of curse it could
> be triggered manually as well.

I think Jeff's solution of passing in a callable is fine. And, if you
really need to do some wild and crazy things, you can pass in a
generic callable :)

Kevin

Kevin Dangoor

unread,
Jan 23, 2006, 5:11:12 PM1/23/06
to turbo...@googlegroups.com
On 1/22/06, Phillip J. Eby <p...@telecommunity.com> wrote:
> Nowhere is there any mention of generic functions or adding methods or
> criteria, but it internally uses a Dispatcher object that does lookups
> based on class and attribute names. So, it's not necessary to expose
> generic functions' complexity directly, if all you want to do is define
> some type of registry of rules based on standardized access patterns.
> RuleDispatch was created in part because I got tired of having to write
> new kinds of registry classes all the time for PEAK, every time there I
> had some new way of looking things up. RuleDispatch lets me focus on
> the app and not on the data structures needed to implement it.

I actually did consider identity.require registering rules in a
context, but I couldn't see the value of doing that over just putting
an expression in the call to require() and eval'ing it.

Kevin

Phillip J. Eby

unread,
Jan 24, 2006, 1:24:48 PM1/24/06
to TurboGears

It all depends on the complexity of the rules. For the use cases
peak.security is intended for, where you have complex business rules to
determine access, and evaluating those rules can result in SQL queries,
you really want to make sure that the relevant tests are done at most
once. If you're eval-ing multiple rules, you can't guarantee that
without additional caching.

For trivial rules, you're right that there's little additional benefit.
PEAK is biased towards "enterprise class" business rules in this area,
and the "equipment shipping" examples given in the peak.security docs
are actually a *simplified* version of some business rules from a real
enterprise application.

The other benefit of course is indirection. Since permissions are
separated from the authentication and authorization rules, it allows
you to distribute an application component that can be customized
without changing its source. The security rules are determined by
context, not by hardcoding. It also allows you to avoid repetition, and
encourages thinking about access control in terms of users and use
cases rather than in terms of individual operations. And even if an
application defines default permissions and rules, these can still be
overridden in a particular deployment by subclassing the context and
defining new operation-to-permission or permission-to-user rules.

Anyway, these are not necessarily benefits for TurboGears' audience;
I'm just pointing out for the sake of anybody following this thread
what the intended benefits of peak.security are, so they can tell for
themselves whether eval() is indeed better for *their* use cases. :)

Kevin Dangoor

unread,
Jan 24, 2006, 2:19:59 PM1/24/06
to turbo...@googlegroups.com
On 1/24/06, Phillip J. Eby <p...@telecommunity.com> wrote:
> Anyway, these are not necessarily benefits for TurboGears' audience;
> I'm just pointing out for the sake of anybody following this thread
> what the intended benefits of peak.security are, so they can tell for
> themselves whether eval() is indeed better for *their* use cases. :)

I do understand the use cases for peak.security, and I'm sure that
some portion of TurboGears users will benefit from that. For the
simple, yet common, cases that identity's current API solves nicely, I
was thinking that eval() was just as good (plus low overhead) as
creating a context that keys on class/method. You have a good point,
though, that someone could create rules externally that override the
individual method controls if it's all going into one big context.

Jorge Godoy

unread,
Jan 24, 2006, 4:29:36 PM1/24/06
to turbo...@googlegroups.com
"Phillip J. Eby" <p...@telecommunity.com> writes:

> The other benefit of course is indirection. Since permissions are
> separated from the authentication and authorization rules, it allows
> you to distribute an application component that can be customized
> without changing its source. The security rules are determined by
> context, not by hardcoding. It also allows you to avoid repetition, and
> encourages thinking about access control in terms of users and use
> cases rather than in terms of individual operations. And even if an
> application defines default permissions and rules, these can still be
> overridden in a particular deployment by subclassing the context and
> defining new operation-to-permission or permission-to-user rules.
>
> Anyway, these are not necessarily benefits for TurboGears' audience;
> I'm just pointing out for the sake of anybody following this thread
> what the intended benefits of peak.security are, so they can tell for
> themselves whether eval() is indeed better for *their* use cases. :)

I definitely hope that this gets into TG soon... That's OK for post-0.9, but
I really like the idea of not repeating a lot of code -- even if they are like
decorators -- and thinking in use cases / users. Today's operation-based
thinking solves the problem for small requirements but it gets a lot in the
way for more complex applications.

--
Jorge Godoy <jgo...@gmail.com>

Jeff Watkins

unread,
Jan 24, 2006, 5:06:03 PM1/24/06
to turbo...@googlegroups.com
Jorge Godoy wrote:
> I definitely hope that this gets into TG soon... That's OK for post-0.9, but
> I really like the idea of not repeating a lot of code -- even if they are like
> decorators -- and thinking in use cases / users. Today's operation-based
> thinking solves the problem for small requirements but it gets a lot in the
> way for more complex applications.

Just in case it's been overlooked, you can now protect an entire tree of
your application using SecureResource and you can declare the identity
predicates in your config file.

For more information:

http://nerd.newburyportion.com/2006/01/refining-the-identity-framework

Reply all
Reply to author
Forward
0 new messages