How do I set the identity upon login.

10 views
Skip to first unread message

Jesse James

unread,
Feb 21, 2007, 7:25:58 PM2/21/07
to TurboGears
Howdy,
I am using SqlAlchemy under TG and Flash (with FlexBuilder 2) for the
UI.
I'm trying to figure out how to get login/logout and @require
decorator to work for me.
I am not walking down the garden path of using Kid and SqlObject so it
is not really set up right out of the box. Rather I am attempting to
leverage the auth framework in TG but with different needs from the
standard template-based app - I need much more explicit rejection of
unauthorized access attempts (not redirects to a login screen). Upon
login, however, it seems that it should be quite straightforward to
setup the identity, yes?

What I need to know is the following:

1. how do I write my own login controller that will explicitly set the
identity for any future requests.
2. how do I logout.

So far, I'm able to add users to DB, no problem. But looking at the
identity code and the saprovider code, I am getting lost (I'm somewhat
of a Python newbie, ex-Java). In Java, you usually have pretty
explicit static typing to use when analysing other folks code. I find
that in Python, this is not possible, thus you really have to dig
quite deep to figure out where things are coming from. I'm not making
much headway there.

Any help will be very much appreciated.
Thanks,
Jesse James

Patrick Lewis

unread,
Feb 22, 2007, 6:57:21 AM2/22/07
to TurboGears
On Feb 21, 7:25 pm, "Jesse James" <joel.re...@gmail.com> wrote:
> Howdy,
> I am using SqlAlchemy under TG and Flash (with FlexBuilder 2) for the
> UI.
> I'm trying to figure out how to get login/logout and @require
> decorator to work for me.
> I am not walking down the garden path of using Kid and SqlObject so it
> is not really set up right out of the box. Rather I am attempting to
> leverage the auth framework in TG but with different needs from the
> standard template-based app - I need much more explicit rejection of
> unauthorized access attempts (not redirects to a login screen). Upon
> login, however, it seems that it should be quite straightforward to
> setup the identity, yes?
>
> What I need to know is the following:
>
> 1. how do I write my own login controller that will explicitly set the
> identity for any future requests.
> 2. how do I logout.
>

In general terms, what identity is doing is associating a 'visit'
session (everyone visiting the site gets a unique visit key) with a
user. This starts out in the visit module (http://tinyurl.com/
376wae). Roughly, this works like:

- Identity receives a new request, and eventually routes it to
identity_from_request
- identity_from_request tries to authenticate via the methods you
specified in the config (default to form,http_auth,visit). form and
http_auth basically check for credentials in the request, and the
visit check (via identity_from_visit) asks the identity provider to
return a user
- if all the authentication methods fail, the identity is set to
anonymous

Ok, that's the authentication path. Now, when a user doesn't have
appropriate permissions, (i.e. the identity.require check fails), an
IdentityFailure exception is raised, which brings up the login form
(http://tinyurl.com/2j3ecm).

Logging out is done by removing the association between the user and
the visit key. This happens in SqlObjectIdentity or SqlAlchemyIdentity
via the logout() method. Or, in a controller, by calling
identity.current.logout()

Ok, so, where does that leave you. I'm not sure, so you may want to
ask more questions. Some things to think about.

If you set identity config options like:

identity.failure_url="/my_failure_url"
identity.source="visit"

You would get rid of the redirect to the login form. my_failure_url
could be a controller that raises an Unauthorized exception, or
perhaps shows an error page. You could then setup your own login form
and controller that explicitly associated the user with the visit key,
using identity.current_provider.validate_identity, and bypass
identity's default form login altogether. The caveat is that the only
way to authenticate will be through your new login form, but it sounds
like that is what you want anyways.

Jesse James

unread,
Feb 24, 2007, 5:03:25 PM2/24/07
to TurboGears
Can you validate this code then (assume for now that password is
cleartext in the DB)?

@tg.expose()
def login(self, username, password):
result = 'ok'
user=User.get_by(user_name=username)
if(user):
if(user.password == password):
identity.set_current_identity(user)
else:
result = 'invalid login'
else:
result = "invalid login"
return result

On Feb 22, 5:57 am, "Patrick Lewis" <patrickhle...@gmail.com> wrote:
> On Feb 21, 7:25 pm, "Jesse James" <joel.re...@gmail.com> wrote:
>
>
>
> > Howdy,
> > I am using SqlAlchemy under TG and Flash (with FlexBuilder 2) for the
> > UI.
> > I'm trying to figure out how to get login/logout and @require
> > decorator to work for me.
> > I am not walking down the garden path of using Kid and SqlObject so it
> > is not really set up right out of the box. Rather I am attempting to
> > leverage the auth framework in TG but with different needs from the
> > standard template-based app - I need much more explicit rejection of
> > unauthorized access attempts (not redirects to a login screen). Upon
> > login, however, it seems that it should be quite straightforward to

> > setup theidentity, yes?


>
> > What I need to know is the following:
>
> > 1. how do I write my own login controller that will explicitly set the

> >identityfor any future requests.


> > 2. how do I logout.
>

> In general terms, whatidentityis doing is associating a 'visit'


> session (everyone visiting the site gets a unique visit key) with a
> user. This starts out in the visit module (http://tinyurl.com/
> 376wae). Roughly, this works like:
>

> -Identityreceives a new request, and eventually routes it to


> identity_from_request
> - identity_from_request tries to authenticate via the methods you
> specified in the config (default to form,http_auth,visit). form and
> http_auth basically check for credentials in the request, and the

> visit check (via identity_from_visit) asks theidentityprovider to
> return a user
> - if all the authentication methods fail, theidentityis set to


> anonymous
>
> Ok, that's the authentication path. Now, when a user doesn't have

> appropriate permissions, (i.e. theidentity.require check fails), an


> IdentityFailure exception is raised, which brings up the login form
> (http://tinyurl.com/2j3ecm).
>
> Logging out is done by removing the association between the user and
> the visit key. This happens in SqlObjectIdentity or SqlAlchemyIdentity
> via the logout() method. Or, in a controller, by callingidentity.current.logout()
>
> Ok, so, where does that leave you. I'm not sure, so you may want to
> ask more questions. Some things to think about.
>

> If you setidentityconfig options like:


>
> identity.failure_url="/my_failure_url"identity.source="visit"
>
> You would get rid of the redirect to the login form. my_failure_url
> could be a controller that raises an Unauthorized exception, or
> perhaps shows an error page. You could then setup your own login form
> and controller that explicitly associated the user with the visit key,

> usingidentity.current_provider.validate_identity, and bypassidentity'sdefault form login altogether. The caveat is that the only

Patrick Lewis

unread,
Feb 24, 2007, 10:21:33 PM2/24/07
to TurboGears
I don't think that will persist outside of the current request (i.e.
the user won't stay logged in). How about something like (untested):

http://paste.turbogears.org/paste/1067

Rick

unread,
Feb 25, 2007, 10:09:36 AM2/25/07
to TurboGears
I haven't tested the code above, but below is what I use to log in a
user (extended from the SA quickstart identity). I believe logging
out is as simple as identity.current.logout()

class User(object):
# ... quickstart boilerplate skipped....
def identity_login(self):
ident = identity.current_provider.authenticated_identity(self)
key = visit.current().key
ident.visit_key = key
identity.set_current_identity(ident)
vi = session.query(VisitIdentity).selectfirst(
VisitIdentity.c.visit_key==key)
if vi is None:
vi = VisitIdentity(visit_key=key, user_id=self.user_id)
session.save(vi)
else:
vi.user_id = self.user_id

Jorge Vargas

unread,
Feb 25, 2007, 12:54:43 PM2/25/07
to turbo...@googlegroups.com
both of you could improve your code with this function.
http://trac.turbogears.org/browser/tags/1.0.1/turbogears/identity/__init__.py#L102

Rick

unread,
Feb 25, 2007, 4:09:42 PM2/25/07
to TurboGears
I did use identity.set_current_identity, but (AFAIK) it doesn't create
the corresponding VisitIdentity object in the database, so I had to do
a bit more to get it to work. If I can get away without the rest of
the boilerplate, I'd love to strip down the code more. Is there some
magic going on that I'm missing?

On Feb 25, 12:54 pm, "Jorge Vargas" <jorge.var...@gmail.com> wrote:
> both of you could improve your code with this function.http://trac.turbogears.org/browser/tags/1.0.1/turbogears/identity/__i...

Patrick Lewis

unread,
Feb 25, 2007, 8:55:45 PM2/25/07
to TurboGears

On Feb 25, 12:54 pm, "Jorge Vargas" <jorge.var...@gmail.com> wrote:

> both of you could improve your code with this function.http://trac.turbogears.org/browser/tags/1.0.1/turbogears/identity/__i...
>

I believe everyone in this thread is already using
set_current_identity. In what way are you suggesting this could be
improved?

Jesse James

unread,
Feb 27, 2007, 9:50:54 PM2/27/07
to TurboGears
ok. now I'm still basically as confused as I was before.
I'm having an 'identity crisis' ... sorry, couldn't resist. :-)

So, we have established that Rick could not seem to get the identity
assignment to 'stick' without the code he presented.
Is that the general consensus ???

my original question remains:
How should I properly log in a user without the boiler plate login
template?

Andrew Grover

unread,
Feb 28, 2007, 3:04:52 AM2/28/07
to turbo...@googlegroups.com
On 2/27/07, Jesse James <joel....@gmail.com> wrote:
> my original question remains:
> How should I properly log in a user without the boiler plate login
> template?

I don't know if it's the best way, but one way is:

identity.current_provider.validate_identity(u.user_name, u.password,
identity.current.visit_key)

Regards -- Andy

Ben Sizer

unread,
Feb 28, 2007, 5:14:19 AM2/28/07
to TurboGears
On Feb 28, 8:04 am, "Andrew Grover" <andy.gro...@gmail.com> wrote:
> I don't know if it's the best way, but one way is:
>
> identity.current_provider.validate_identity(u.user_name, u.password,
> identity.current.visit_key)

Surely there must be a way to log in a user without having to provide
a password. Otherwise this is a restriction on many other types of
authentication.

--
Ben Sizer

Patrick Lewis

unread,
Feb 28, 2007, 8:58:25 AM2/28/07
to TurboGears
On Feb 27, 9:50 pm, "Jesse James" <joel.re...@gmail.com> wrote:
> ok. now I'm still basically as confused as I was before.
> I'm having an 'identity crisis' ... sorry, couldn't resist. :-)
>
> So, we have established that Rick could not seem to get the identity
> assignment to 'stick' without the code he presented.
> Is that the general consensus ???
>
> my original question remains:
> How should I properly log in a user without the boiler plate login
> template?

I think my PasteBin code (in this thread) should work, as well as
Rick's code (if you can get a User object).

Have you tried either of these and had problems?

Patrick Lewis

unread,
Feb 28, 2007, 9:10:18 AM2/28/07
to TurboGears

What types of authentication are there that don't require a password
or secret of some type? It's an honest question; I'm not familiar with
any.

Ben Sizer

unread,
Feb 28, 2007, 11:09:16 AM2/28/07
to TurboGears

Well for starters, there might actually be a password, but it's
handled remotely. eg. You may submit the username and password to some
sort of trusted service on the local network, which can then grant or
deny access. You may have existing code for doing this, and won't want
to hack the identity provider or whatever it is to have to relay that
password on (which I assume is possible, though I haven't checked).

Or you might just grant access based on IP address, such as admin
rights automatically granted to localhost. Or it could just be a low-
security shared system, eg. an intranet wiki, where you just go by
username and don't want to burden people with passwords.

Maybe you don't store any important data that persists across visits,
and instead just want to equate one 'user' with one extended visit to
the site, but find it convenient to use identity to tie the data
together across multiple HTTP requests, after an implicit login.

Perhaps you're sharing a domain with a legacy PHP site, and while
slowly migrating over to Turbogears, you want the cookie that your PHP
login script sets to allow you to access restricted parts of your TG
app.

Or you might desire some sort of 'su' functionality where someone
logged in as an administrator can log in as someone else instantly -
for this you'd want to be able to just reassign the identity
accordingly.

Sure, many of these are somewhat uncommon, and I expect many or most
can be hacked around with new identity providers, but I don't know how
easily more than one such provider might co-exist within one app for
example. I think it would be beneficial to expose a function that
allows people with advanced authentication purposes to simply reassign
the current user.

--
Ben Sizer

Rick

unread,
Feb 28, 2007, 6:40:27 PM2/28/07
to TurboGears
Actually, I don't think that validate_identity will work if you have
password encryption turned on (which you should)....

On Feb 28, 5:14 am, "Ben Sizer" <kylo...@gmail.com> wrote:

Jesse James

unread,
Mar 4, 2007, 3:58:19 PM3/4/07
to TurboGears
yes. Well, then, in this case you would especially want to just bypass
the boilerplate code and just reassign the user to this session. Yes?

Jesse James

unread,
Mar 4, 2007, 4:04:11 PM3/4/07
to TurboGears
If you are referring to this code:

def login(self,username,password):
ident = tg.identity.current_provider.validate_identity(
username, password, cherrypy.request.tg_visit.key)
if ident:
result = 'ok'
else:
# credentials weren't valid, so user is anonymous
ident = tg.identity.current_provider.anonymous_identity()
result = 'invalid login'
# manually set identity in case we
# want to use it elsewhere in this request
tg.identity.set_current_identity(ident)
return result

then, no, I haven't tried it yet, but I now have this high on my todo
list.
Thanks, I'll let you know ASAP.
Jesse

Ben Sizer

unread,
Mar 5, 2007, 11:32:06 AM3/5/07
to TurboGears
On Mar 4, 8:58 pm, "Jesse James" <joel.re...@gmail.com> wrote:
> yes. Well, then, in this case you would especially want to just bypass
> the boilerplate code and just reassign the user to this session. Yes?

Unless someone has a good way of delegating identity authentication to
outside sources that handles that at a higher level, yes.

If identity could easily accommodate multiple providers, and could log
in a given user via an appropriate function without having to supply
any sort of password, then you wouldn't need to assign anything
directly. I'd prefer the framework to evolve to better handle those
situations.

--
Ben Sizer


Reply all
Reply to author
Forward
0 new messages