On Thursday March 12, 2009 13:16:51 Jorge Vargas wrote:
> >> in order to overwrite the functionality of CRC to allow a different
> >> require decorator you have this 4 lines
> >>
> >> @require(in_group('managers'))
> >> @expose()
> >> def get_all(self,*args,**kw):
> >> return super(RegistrationController,self).get_all(*args,**kw)
> >>
> >> I guess you could fetch the method from the parent class and decorate
> >> it but I find that more cryptic than the 4 lines above. In general
> >> this question should be.
> >
> > Ahh, right, I see what you mean!
> >
> > Yes, I was afraid that'd be true.
> >
> > Well, to make things easier in the Rest controller, I can make
> > repoze.what- pylons support an alternative to the @ActionProtector
> > decorator (@require's parent), so that you could have:
> > decorate_with_require(RegistrationController.get_all,
> > in_group('managers'))
>
> that seems less ugly but it doesn't fits with the class dispatch
> stuff, where will that line go? at the class? or outside of it?
Outside, which makes it uglier.
> > instead of:
> > RegistrationController.get_all = require(in_group('managers'))\
> > (RegistrationController.get_all)
> >
> > But I'm not too fond of this solution because it's not simple enough, I
> > think it's possibly better to handle it in the Rest controller itself,
> > somehow.
>
> well the simplest solution will be to provide a hook like it's done
> for the forms. so you will do something like.
>
> class RegistrationController(CrudRestController):
> ...
> edit_require = All(editor_is_current(),in_group('managers'))
>
> And internally CRC will do @require(edit_require)
That seems better, although still not elegant -- I don't have a better
solution in mind, though.
> >> Is there a way to declare the controller method somewhere and decorate
> >> it with auth in a second stage?
> >
> > I guess
> > RegistrationController.get_all = require(in_group('managers'))\
> > (RegistrationController.get_all)
> > would work.
> >
> > But it's ugly.
>
> I think this is something we have to look after specially for TG2.1
> when we plan to have re-distributable component. I can totally see
> someone wanting to get auth working in a different way than what the
> original author intended too. For example imagine someone writes
> tgext.wiki, which is open to the world to read but you need to login
> to write, and I want to use that wiki to keep my personal items and
> let some people see some pages, I'll have to basically subclass each
> controller in the tgext.wiki package to modify it's auth. I find that
> is a horrible bloat.
Agreed.
> >> >> 3- why repoze.what made All ? can't we use any/all from python we
> >> >> have plenty of ways of providing that in the TG1 codebase
> >> >
> >> > There's no way to do that. They need the environ to be evaluated.
> >>
> >> seriously? you can't do this with __call__. according to help(all) it
> >> simply calls bool(x) so I assume there has to be a way to stick that
> >> in there.
> >
> > bool(predicate) is not a valid option. It assumes that the Predicate
> > class has been monkey patched with the buggy trick of __nonzero__.
>
> is not? I assumed that was the solution for
> http://trac.turbogears.org/ticket/2205
No, that's just a horrible *TG2/Pylons-specific* misfeature which I regret to
have implemented because it's dirty and makes applications unportable.
> >> >> 4- look at how awful is that custom predicate to simply figure out if
> >> >> the current user is the one trying to be edited, I have left the
> >> >> pprint in there to give you an idea of how horrible it was for me to
> >> >> find out how to query for him.
> >> >
> >> > (Answered above)
> >>
> >> I think you oversimplified the problem, there is no "User.user_name"
> >> in the url. therefore i need to fetch that record and compare it to
> >> the current user.
> >
> > If you're using the artificial key "user_id" in the URL, yes, you have to
> > use it, unless you tell repoze.what.plugins.sql to pass User.user_id as
> > the user identifier.
>
> aritficial key? huh? please stop thinking about auth for a minute :)
> this is REST in rest resources have a key, keys for convenience are
> numeric and unique, the fact that this key happens to refer to the
> user is a mere coincidence.
"artificial/surrogate/sequence key" is a term used in database design: :)
http://en.wikipedia.org/wiki/Surrogate_key
http://en.wikipedia.org/wiki/Natural_key
I was talking from a database perspective, not in the context of REST.
It's just a matter of taste, like the answer to "what text editor should I
use?", but I'd have loved to see quickstarted apps with natural keys and I
think it would've avoided that you were concerned about this (because I
understand your concern).
> >> >> 4.1- why is repoze.what.userid == User.user_name ??
> >> >
> >> > Don't ask me, you wrote it ;-) I don't even know you used the DB =)
> >>
> >> huh? repoze.what.userid is loaded by repoze.what from the "user_name"
> >> field, it is inconsistent as the User.user_id attribute is a number
> >> (autogenerated index) while repoze.what.userid is a string (stored in
> >> User.user_name)
> >
> > Inconsistent? repoze.what doesn't have to be "consistent" with TG.
>
> oh rly?
Of course! Although it was born in the TG project and at present it's mostly
used because of TG2, it doesn't mean that now it has to evolve being
consistent with TG2's style.
> > "userid" is _the_ _right_ name, since it's valid for strings and numbers.
> > "user_name" is a wrong name, since it's limited to strings.
>
> I'm not talking about the name but you are totally right. you are
> loading the "userid" with the "user_name" why?
Since in quickstarted applications both User.user_id and User.user_name work
as valid user identifiers, I decided to make repoze.what.plugins.sql pass the
value of User.user_name to repoze.what, so that it'll be used as the user's Id
-- this way, people would be able to use is_user() as they'd expect.
> > And as far as repoze.what is concerned, the user identifier can be
> > anything (e.g., a binary value, an ASCII string, an Unicode string, a
> > number), not just a name (i.e., an ASCII or Unicode string).
>
> This is great, but why is it loaded from username instead of user id?
> is this simply for legacy reasons?
Yes, as well as because of what I mentioned in the paragraph above.
> > That TG2 seem to prefer artificial keys over natural keys is another
> > subject, but I think those models should've been using natural keys since
> > day 1; you wouldn't be concerned about this otherwise.
>
> Assuming you mean "natural" as "human readable" I have to disagree.
> You have a ton of issues with non-sequencial primary keys in any
> environment. You almost always need a UUID that is "artificial" to
> ensure data integrity and (formerly speed). Even the most "modern"
> storage engines support some sort of "artificial" key because history
> has proven you need them.
Of course sometimes you need them.
I just think that, where reasonable, natural keys should be used. And nowadays
referential integrity shouldn't be a concern (when using modern RDBMSs).
> If what you are saying is that the default TG identity model should
> drop all the id keys for User,Group and Permission. That will cause a
> big set of issues, not because of backwards compatibility but because
> it will collide with how databases work. Sure you can get away with
> non int primary keys but it is not how a lot of stuff works.
There would be no backwards incompatibility, at all. But can you please give
an example about the rest?
> Are you suggesting we go with slug for keys for everything? you can't
> make URLs support all types of keys URLs have a very limited charset,
> not to mention casesensitive issues and .... well all the problems
> slugs have.
Only Web application developers like you or like me can cause such problems if
we don't do our job correctly. I don't think the problems you mention are in
HTTP agents or servers; and if they were, they'd be bugs which should have
fixed many centuries ago.
I have Web sites with URLs in Arabic, Vietnamese, Chinese, Russian, etc., and
I've never had problems, not even in crappy agents like IE (even old
versions). Don't believe me? See it yourself:
http://www.honalinux.org/
http://www.pereidinalinux.org/
http://www.dunglinux.org/
The only issue is that old agents may display those URLs encoded (not
decoded). That's it: They *might* look ugly in old agents, depending on the
language used.
But anyway: No, I'm not suggesting we use natural keys "for everything". Just
for User, Group and Permission, because from my point of view it's reasonable
to use them there, at least there.
> Last but not least not everyone gets to work on a cool 2009 project,
> and enough people with legacy systems depend on "artificial keys"
Natural keys support is a good or bad as artificial keys'. So no RDBMS on the
earth "depends" on artificial keys.
Artificial and natural keys are only in our minds as DB designers. There's no
RDBMS that claims "natural key support" or "artificial key support". It's all
about the way you structure data, the way you see it.
I guess you're confused with another thing: Foreign keys, since old RDBMSs may
have a lack of referential integrity support. And of course, that issue will
be present with both artificial and natural keys.
Or possibly you're confused with the use of non integers as primary keys:
Maybe the first RDBMS ever supported only integers as primary keys; and then
again, that's independent of artificial or natural keys, since natural keys
can be numbers, not only strings... Just like an artificial key can be a
string, not a number.
> > It doesn't make any sense for an authorization software to have two have
> > identifiers for the same user.
> >
> > Nevertheless, repoze.what v2 will support credential loaders (repoze.who
> > MD provider-like stuff) for developers who want to load additional
> > credentials to use them in their custom predicate checkers -- but of
> > course the built-in predicate checkers will only use built-in credentials
> > (this is, is_user will continue using repoze.what.userid).
> >
> >> Also related, what will happen here if the user changes his username?
> >
> > Nothing interesting, if you wrote your custom predicates correctly (i.e.,
> > in a future-proof way).
>
> please enlighten us with future-proof predicate that depend on the
> content of a now variable.
(That phrase in my previous email was misleading, sorry, this should clarify
what I meant by that).
I wasn't talking about something in particular nor something people should
worry about. I meant, for example, that if your predicate is evaluated using a
variable set in the URL, it shouldn't be compared against things you're not
sure you'll have in the future.
The thing is that I don't think you should worry if users change their
identifiers, unless you're using the is_user() predicate.
> >> sightly related didn't we used to have repoze.what.user (the whole db
> >> user instance) stored in the environ?
> >
> > No, never. The user object is in the repoze.who identity dict.
>
> right, but we can't use that because you are getting rid of it for
> r.what v2 correct?
It'd still work because if you continue using repoze.who and repoze.what,
you'd have to add the repoze.who middleware right before repoze.what's. Then,
when repoze.what is called, you'd already have the repoze.who identity dict
available.
I don't like that approach too much, I find it OK-ish (i.e., I'm not totally
opposed to it). For situations like this is why I'll implement the so-called
credential loaders/providers.
> >> shouldn't we be using that
> >> instead of repoze.what.userid for comparations?
> >
> > That'd be ugly for obvious reasons. In a nutshell: You'd be limiting part
> > of your authorization system to a _particular_ setup of your
> > identification system.
>
> I'm totally lost here, you are saying to me that my "authorization"
> system should only look for one key (the "natural" id). and that I
> have no "permission" to query my system for it's group or permission
> because I'll be limiting myself to my authentication system? the whole
> point of having the userid somewhere is for me to LOOK for what he can
> do.
No, I wasn't talking about anything related to that.
What I meant is that, for example, if you move your users' data to an LDAP
server, those predicates using the user object will break -- that's another
example of non "future-proof" predicates.
> >> @expose('coolpackage.cooltemplate')
> >> @require(Any(is_user('admin'), self_user()))
> >> def edit(self, username):
> >> if 'admin' == request.identity.get('repoze.who.userid'):
> >> RegistrationController.edit_form = full_user_form
> >> else:
> >> RegistrationController.edit_form = limited_user_form
> >> return {'username': username}
> >>
> >> which is really odd not to mention will probably cause a big havoc. As
> >> swapping that widget on the fly may be an issue.
> >
> > You're talking about validators? Yeah, that may be a problem in Rest
> > controllers.
>
> I'm talking about how limited this seems. from both point not looking
> who to blame but where to solve this.
I can't talk too much about it because, although I've read the docs for REST
controllers, I've not used them yet. So I'm possibly not the right person to
comment on that, sorry.
To sum up, I want to say that authorization support in rest controllers can be
improved. I just don't know how because I've not even used them yet.
Saludos!
(What a long email! ;-) )
--
Gustavo Narea <xri://=Gustavo>.
| Tech blog: =Gustavo/(+blog)/tech ~ About me: =Gustavo/about |
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears Trunk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/turbogears-trunk?hl=en
-~----------~----~----~----~------~----~------~--~---