Authentication for services

161 views
Skip to first unread message

jcorbett

unread,
May 17, 2009, 9:14:20 PM5/17/09
to web2py Web Framework
I love the service framework, however I am interested in being able to
authenticate users. With json/jsonrpc this shouldn't be too hard as
the browser that the ajax request would come from would have the same
session.

Particularly I am concerned with writing an xmlrpc service that
requires authentication. The Auth class doesn't seem to expose any of
the lower level logic for authentication (like a login function that
takes a username and a password). Any ideas on how I can do this.
I'm not afraid of writing my own implimentation, however I would love
to piggy back off what is already there.

I would figure I would want to have a login function that would create
a session key (limited lifetime), and each function would be required
to provide that key.

Any ideas would be appreciated.

Jason Corbett
BTW I love the simplicity of web2py, it took me maybe 2-3 hours to
write a simple app that was even themed.

mdipierro

unread,
May 17, 2009, 11:22:14 PM5/17/09
to web2py Web Framework
I need to look into this. I do not think there can be a generic
approach. Each protocol has its own quirks and some do not handle
session or authenication.

Massimo

Dan

unread,
May 29, 2009, 9:15:26 PM5/29/09
to web2py Web Framework
Reviving this thread from before... I would like to have a shell
script use wget to authenticate itself and access the data in a web2py
application, but I haven't been able to get the web2py app to accept
the post'ed email and password information, which I sent to the user/
login URL. Is this the right way to do it?

I see some passing references to alternate authorization methods in
the documentation and the code, but I haven't been able to get much
detail on what those might be. For example-

http://mdp.cti.depaul.edu/examples/default/tools#authentication :
"The Auth calls can be extended, personalized, and replaced by other
authentication mechanisms which expose a similar interface."

and in http://mdp.cti.depaul.edu/examples/static/epydoc/web2py.gluon.tools-pysrc.html#Auth.login
:
644 if not user:
645 ## try alternate login methods
646 for login_method in
self.settings.login_methods:
647 if login_method != self and \
648 login_method(request.vars
[username],
649
request.vars.password):
650 user = self.get_or_create_user
(form.vars)


Is there a place where I can find out more about what already exists,
or how to go about getting something like what the original message in
this thread described?

Dan


On May 17, 8:22 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> I need to look into this. I do not think there can be a generic
> approach. Each protocol has its own quirks and some do not handle
> session or authenication.
>
> Massimo
>
> On May 17, 8:14 pm, jcorbett <jasoncorb...@gmail.com> wrote:
>
> > I love the service framework, however I am interested in being able to
> > authenticate users.  With json/jsonrpcthis shouldn't be too hard as
> > the browser that the ajax request would come from would have the same
> > session.
>
> > Particularly I am concerned with writing an xmlrpc service that
> > requires authentication.  TheAuthclass doesn't seem to expose any of

Dan

unread,
May 31, 2009, 11:43:11 PM5/31/09
to web2py Web Framework
Since my last message on this thread, I came up with a patch to the
Auth.login() code that lets me do what I need, so figured I should
post it here. Let me know if you see any issues with this approach (or
improvements to it).

To recap, what I want to do is to let a script runing wget (not a
browser) login and then work with some parts of the app that require
membership in groups. I want to pass the user's name and password to
the login form using post variables in the URL. This is not normally
possible with web2py's Auth.login() function, so it needs to be
modified, like this-

referring to source code here: http://www.web2py.com/examples/static/epydoc/web2py.gluon.tools-pysrc.html#Auth
Change these 3 lines ...
622 if FORM.accepts(form, request.vars, session,
623 formname='login',
624 onvalidation=onvalidation):

... to be these 3 lines:
if username in request.vars.keys() and request.vars.password and \
FORM.accepts(form, request.vars,
formname=None, onvalidation=onvalidation):

This change lets the form take the username and password from the
URL's post variables (or the form itself - but not both of course).
Then my script will login using wget's optional arguments "--keep-
session-cookies --save-cookies=" when submitting the user name and
password to the app's login function. These wget options store the
session cookie in a local file. Then subsequent wget calls to the
restricted parts of the app can use those cookies as a token to gain
access with the option "--load-cookies=".

Apologies for straying a bit from the original use case of this
thread, but perhaps it's general approach will be a helpful hint.

Also: I don't fully understand what the purpose of the "formname"
parameter is, or why it was necessary to None-ify it. If someone can
explain this to me, I'd appreciate it.

Dan



On May 29, 6:15 pm, Dan <danbr...@gmail.com> wrote:
> Reviving this thread from before... I would like to have a shell
> script use wget to authenticate itself and access the data in a web2py
> application, but I haven't been able to get the web2py app to accept
> the post'ed email and password information, which I sent to the user/
> login URL. Is this the right way to do it?
>
> I see some passing references to alternate authorization methods in
> the documentation and the code, but I haven't been able to get much
> detail on what those might be. For example-
>
> http://mdp.cti.depaul.edu/examples/default/tools#authentication:
> "The Auth calls can be extended, personalized, and replaced by other
> authentication mechanisms which expose a similar interface."
>
> and inhttp://mdp.cti.depaul.edu/examples/static/epydoc/web2py.gluon.tools-p...

mdipierro

unread,
Jun 1, 2009, 12:51:27 AM6/1/09
to web2py Web Framework
OK. As you request since the latest version in trunk you can do

@auth.requires_login()
def index(): return 'hello world'

and access it with

curl -u username:password http://127.0.0.1:8000/app/default/index

or

curl http://username:pass...@127.0.0.1:8000/app/default/index

In the latter case username and password have to be encoded by
urllib.quote()

works for services too.

Massimo

On May 31, 10:43 pm, Dan <danbr...@gmail.com> wrote:
> Since my last message on this thread, I came up with a patch to the
> Auth.login() code that lets me do what I need, so figured I should
> post it here. Let me know if you see any issues with this approach (or
> improvements to it).
>
> To recap, what I want to do is to let a script runing wget (not a
> browser) login and then work with some parts of the app that require
> membership in groups. I want to pass the user's name and password to
> the login form using post variables in the URL. This is not normally
> possible with web2py's Auth.login() function, so it needs to be
> modified, like this-
>
> referring to source code here:http://www.web2py.com/examples/static/epydoc/web2py.gluon.tools-pysrc...

Dan

unread,
Jun 1, 2009, 11:10:10 AM6/1/09
to web2py Web Framework
thanks Massimo - that works great using curl, but I couldn't get it to
work using wget, eg.

wget --user=username --password=password -O - http://127.0.0.1:8000/app/default/index

Any suggestions?

On May 31, 9:51 pm, mdipierro <mdipie...@cs.depaul.edu> wrote:
> OK. As you request since the latest version in trunk you can do
>
> @auth.requires_login()
> def index(): return 'hello world'
>
> and access it with
>
>    curl -u username:passwordhttp://127.0.0.1:8000/app/default/index
>
> or
>
>    curl http://username:passw...@127.0.0.1:8000/app/default/index

mdipierro

unread,
Jun 1, 2009, 11:15:21 AM6/1/09
to web2py Web Framework
Try

wget http://username:pass...@127.0.0.1:8000/app/default/index

On Jun 1, 10:10 am, Dan <danbr...@gmail.com> wrote:
> thanks Massimo - that works great using curl, but I couldn't get it to
> work using wget, eg.
>
> wget --user=username --password=password -O -http://127.0.0.1:8000/app/default/index

Dan

unread,
Jun 1, 2009, 1:23:00 PM6/1/09
to web2py Web Framework
That didn't work for me either. Here is the command I tried:
wget -O - http://username=p...@127.0.0.1:8000/app/default/index
I see the login form, not the "hello world" page. and I used urllib to
encode the "@" character in the username. it replaces it with "%40"

and the curl equivalent of this didn't work for me either.
curl http://username=pass...@127.0.0.1:8000/app/default/index
it responds with only one line:
You are being redirected <a href="/app/default/login">here</a>


On Jun 1, 8:15 am, mdipierro <mdipie...@cs.depaul.edu> wrote:
> Try
>
> wget http://username:passw...@127.0.0.1:8000/app/default/index

Dan

unread,
Jun 1, 2009, 1:38:36 PM6/1/09
to web2py Web Framework
Success!
Adding the "--auth-no-challenge" parameter to the wget command is
necessary

wget --auth-no-challenge --user=[username] --password=[password]
http://127.0.0.1:8000/app/default

thanks for your patience, and for making the change to the code.
Dan




On Jun 1, 10:23 am, Dan <danbr...@gmail.com> wrote:
> That didn't work for me either. Here is the command I tried:
> wget -O - http://username...@127.0.0.1:8000/app/default/index
> I see the login form, not the "hello world" page. and I used urllib to
> encode the "@" character in the username. it replaces it with "%40"
>
> and the curl equivalent of this didn't work for me either.
> curl http://username=passw...@127.0.0.1:8000/app/default/index

Alexei Vinidiktov

unread,
Jun 3, 2009, 10:28:03 PM6/3/09
to web...@googlegroups.com
I've tried this with the pyjamas tutorial and it didn't work. I've
enabled user registration and registered a user whose credentials are
used in the URL below. I got a server error when a function requiring
user authentication was called.

I changed the line

JSONProxy.__init__(self, "../../default/call/jsonrpc", ["getTasks",
"addTask","deleteTask"])

to read

JSONProxy.__init__(self,
"http://myemail%40gmail.com%3Amypa...@127.0.0.1:8000/pyjamas/default/call/jsonrpc",
["getTasks", "addTask","deleteTask"])

What am I missing?

Thanks.
--
Alexei Vinidiktov

Hasanat Kazmi

unread,
Jun 23, 2009, 8:31:37 PM6/23/09
to web2py Web Framework, Alexei Vinidiktov, mdipierro
Here is an interesting behavior.
i have following function

@auth.requires_login()
@service.json
@service.jsonrpc
def acceptme():
return "accepted"

in this case, whatever username and password I give, I get returned
"accepted" but if I put @auth.requires_login() after @service.jsonrpc,
it always returns me "Object does not exist" .

I call it like this:
http://hasanatkazmi%40gmail.com:*****@localhost:8000/sahana/admin/call/json/acceptme

Anyone has an idea whats going on?

On Jun 4, 7:28 am, Alexei Vinidiktov <alexei.v...@gmail.com>
wrote:
> I've tried this with the pyjamas tutorial and it didn't work. I've
> enabled user registration and registered a user whose credentials are
> used in the URL below. I got a server error when a function requiring
> user authentication was called.
>
> I changed the line
>
> JSONProxy.__init__(self, "../../default/call/jsonrpc", ["getTasks",
> "addTask","deleteTask"])
>
> to read
>
> JSONProxy.__init__(self,
> "http://myemail%40gmail.com%3Amypa...@127.0.0.1:8000/pyjamas/defaul...",
> ["getTasks", "addTask","deleteTask"])
>
> What am I missing?
>
> Thanks.
>
>
>
> On Mon, Jun 1, 2009 at 12:51 PM, mdipierro <mdip...@cs.depaul.edu> wrote:
>
> > OK. As you request since the latest version in trunk you can do
>
> > @auth.requires_login()
> > def index(): return 'hello world'
>
> > and access it with
>
> >   curl -u username:passwordhttp://127.0.0.1:8000/app/default/index
>
> > or
>
> >   curlhttp://username:pass...@127.0.0.1:8000/app/default/index
>
> > In the latter case username and password have to be encoded by
> > urllib.quote()
>
> > works for services too.
>
> > Massimo
>
> > On May 31, 10:43 pm, Dan <danbr...@gmail.com> wrote:
> >> Since my last message on this thread, I came up with a patch to the
> >>Auth.login() code that lets me do what I need, so figured I should
> >> post it here. Let me know if you see any issues with this approach (or
> >> improvements to it).
>
> >> To recap, what I want to do is to let a script runing wget (not a
> >> browser)loginand then work with some parts of the app that require
> >> membership in groups. I want to pass the user's name and password to
> >> theloginformusing post variables in the URL. This is not normally
> >> possible with web2py'sAuth.login() function, so it needs to be
> >> modified, like this-
>
> >> referring to source code here:http://www.web2py.com/examples/static/epydoc/web2py.gluon.tools-pysrc...
> >> Change these 3 lines ...
> >>  622          ifFORM.accepts(form, request.vars, session,
> >>  623                          formname='login',
> >>  624                          onvalidation=onvalidation):
>
> >> ... to be these 3 lines:
> >> if username in request.vars.keys() and request.vars.password and \
> >>        FORM.accepts(form, request.vars,
> >>             formname=None, onvalidation=onvalidation):
>
> >> This change lets theformtake the username and password from the
> >> URL's post variables (or theformitself - but not both of course).
> >> Then my script willloginusing wget's optional arguments "--keep-
> >> session-cookies --save-cookies=" when submitting the user name and
> >> password to the app'sloginfunction. These wget options store the
> >> session cookie in a local file. Then subsequent wget calls to the
> >> restricted parts of the app can use those cookies as a token to gain
> >> access with the option "--load-cookies=".
>
> >> Apologies for straying a bit from the original use case of this
> >> thread, but perhaps it's general approach will be a helpful hint.
>
> >> Also: I don't fully understand what the purpose of the "formname"
> >> parameter is, or why it was necessary to None-ify it. If someone can
> >> explain this to me, I'd appreciate it.
>
> >> Dan
>
> >> On May 29, 6:15 pm, Dan <danbr...@gmail.com> wrote:
>
> >> > Reviving this thread from before... I would like to have a shell
> >> > script use wget to authenticate itself and access the data in a web2py
> >> > application, but I haven't been able to get the web2py app to accept
> >> > the post'ed email and password information, which I sent to the user/
> >> >loginURL. Is this the right way to do it?
>
> >> > I see some passing references to alternate authorization methods in
> >> > the documentation and the code, but I haven't been able to get much
> >> > detail on what those might be. For example-
>
> >> >http://mdp.cti.depaul.edu/examples/default/tools#authentication:
> >> > "TheAuthcalls can be extended, personalized, and replaced by other
> >> > > > the lower level logic for authentication (like aloginfunction that
> >> > > > takes a username and a password).  Any ideas on how I can do this.
> >> > > > I'm not afraid of writing my own implimentation, however I would love
> >> > > > to piggy back off what is already there.
>
> >> > > > I would figure I would want to have aloginfunction that would create

mdipierro

unread,
Jun 23, 2009, 8:47:38 PM6/23/09
to web2py Web Framework
You cannot mix authorization and services this way. It is complicated
an there are many cases....

If you have

@auth.requires_login()
def acceptme():
return 'accepted'

you can call "http://..../acceptme.json" and you will get a JSON
response. You do not need the decorator.

@auth.requires_login()
@service.json()
def acceptme():
return 'accepted'
def run(): return service()

exposes "http://..../service/json/acceptme" before requiring login.

@service.json()
def acceptme():
return 'accepted'
@auth.requires_login()
def run(): return service()

this should work but will require login for all services

@service.json()
@auth.requires_login()
def acceptme():
return 'accepted'
def run(): return service()

this is not completely clear to me why does not work but I see some
logical problems.

Massimo



On Jun 23, 7:31 pm, Hasanat Kazmi <hasanatka...@gmail.com> wrote:
> Here is an interesting behavior.
> i have following function
>
> @auth.requires_login()
> @service.json
> @service.jsonrpc
> def acceptme():
>     return "accepted"
>
> in this case, whatever username and password I give, I get returned
> "accepted" but if I put @auth.requires_login() after @service.jsonrpc,
> it always returns me "Object does not exist" .
>
> I call it like this:http://hasanatkazmi%40gmail.com:*****@localhost:8000/sahana/admin/cal...
>
> Anyone has an idea whats going on?
>
> On Jun 4, 7:28 am, Alexei Vinidiktov <alexei.vinidik...@gmail.com>
> wrote:
>
> > I've tried this with the pyjamas tutorial and it didn't work. I've
> > enabled user registration and registered a user whose credentials are
> > used in the URL below. I got a server error when a function requiring
> > user authentication was called.
>
> > I changed the line
>
> > JSONProxy.__init__(self, "../../default/call/jsonrpc", ["getTasks",
> > "addTask","deleteTask"])
>
> > to read
>
> > JSONProxy.__init__(self,
> > "http://myemail%40gmail.com%3Amypassw...@127.0.0.1:8000/pyjamas/defaul...",
> > ["getTasks", "addTask","deleteTask"])
>
> > What am I missing?
>
> > Thanks.
>
> > On Mon, Jun 1, 2009 at 12:51 PM, mdipierro <mdipie...@cs.depaul.edu> wrote:
>
> > > OK. As you request since the latest version in trunk you can do
>
> > > @auth.requires_login()
> > > def index(): return 'hello world'
>
> > > and access it with
>
> > >   curl -u username:passwordhttp://127.0.0.1:8000/app/default/index
>
> > > or
>
> > >   curlhttp://username:passw...@127.0.0.1:8000/app/default/index

David Watson

unread,
Jul 16, 2009, 3:07:09 AM7/16/09
to web2py Web Framework
I'm using web2py 1.65.5 with google app engine.

I've run into a problem with request.args in relation to my json
calls:

@service.json
def json_read_nologin():
return request.args[0]

or the same function defined sans the service decorator, both work
fine, as long as I don't pass something containing an @ sign, i.e.

http://localhost:8000/init/default/json_read_nologin/us...@domain.com

this generates an invalid request even if url encoded:

http://localhost:8000/init/default/json_read_nologin/user%40domain.com

I'm not sure what I'm doing wrong here but this behavior doesn't seem
like what I'd expect.

Thanks,
David
> > > >> > > > authenticate users.  Withjson/jsonrpcthis shouldn't be too hard as

mdipierro

unread,
Jul 16, 2009, 9:18:40 AM7/16/09
to web2py Web Framework
web2py validates the URL and does allow the @ sign in the URL, only
alphanumaric characters, _, - and non-consecutive . and /.

On Jul 16, 2:07 am, David Watson <davidthewat...@gmail.com> wrote:
> I'm using web2py 1.65.5 with google app engine.
>
> I've run into a problem with request.args in relation to my json
> calls:
>
> @service.json
> def json_read_nologin():
>     return request.args[0]
>
> or the same function defined sans the service decorator, both work
> fine, as long as I don't pass something containing an @ sign, i.e.
>
> http://localhost:8000/init/default/json_read_nologin/u...@domain.com

Jonathan Lundell

unread,
Jul 16, 2009, 9:35:01 AM7/16/09
to web...@googlegroups.com
On Jul 16, 2009, at 6:18 AM, mdipierro wrote:

>
> web2py validates the URL and does allow the @ sign in the URL, only
> alphanumaric characters, _, - and non-consecutive . and /.

Did you mean "does not allow"? Shouldn't the validation be more
generous in the args section? There's nothing wrong with this as an
http URL:

http://localhost:8000/init/default/json_read_nologin/user%40domain.com

(Where does the validation happen?)

Jonathan Lundell

unread,
Jul 16, 2009, 10:07:43 AM7/16/09
to web...@googlegroups.com
On Jul 16, 2009, at 6:35 AM, Jonathan Lundell wrote:

>
> On Jul 16, 2009, at 6:18 AM, mdipierro wrote:
>
>>
>> web2py validates the URL and does allow the @ sign in the URL, only
>> alphanumaric characters, _, - and non-consecutive . and /.
>
> Did you mean "does not allow"? Shouldn't the validation be more
> generous in the args section? There's nothing wrong with this as an
> http URL:
>
> http://localhost:8000/init/default/json_read_nologin/user%40domain.com
>
> (Where does the validation happen?)

OK, that last was a dumb question, since I just finished reformatting
regex_url.

So here's the validation for args: ([\w\-][\=\./]?)+

I don't want to make a proposal here, since I have no idea what args
consumers are assuming for validation. But it does seem reasonable in
the abstract to allow a little more than this pattern permits.

(And I could see piggybacking on the IS_HTTP_URL validator for the
first cut.)

mdipierro

unread,
Jul 16, 2009, 10:54:14 AM7/16/09
to web2py Web Framework
This is a big can of worms.

@ is a reserved character and if used in urls, it should be encoded. I
do not want encoded chars in the URL because this defies the all
purpose: readability by humans.

Massimo
> ...
>
> read more »

mdipierro

unread,
Jul 16, 2009, 10:57:50 AM7/16/09
to web2py Web Framework
PS.

You can do still handle any type of special char in the url by using
routes and mapping some args into a vars.
> ...
>
> read more »

David Watson

unread,
Jul 16, 2009, 11:41:54 AM7/16/09
to web2py Web Framework
Perhaps ironically, the case I'm talking about is machine-to-machine,
no humans involved. While I understand the need for human readability,
that restriction seems like throwing the baby out with the bathwater.
That said, I'll have a look at routes.py.
> ...
>
> read more »

Jonathan Lundell

unread,
Jul 16, 2009, 12:14:45 PM7/16/09
to web...@googlegroups.com
On Jul 16, 2009, at 7:57 AM, mdipierro wrote:

> PS.
>
> You can do still handle any type of special char in the url by using
> routes and mapping some args into a vars.

I suppose that solves the immediate problem, but along with the
entirely legitimate role of web2py in machine-to-machine
communications, where human readability is irrelevant, there's no real
enforcement of readability anyway. Which of these is more human-
readable, anyway?

http://localhost:8000/init/default/json_read_nologin/user%40domain.com
http://localhost:8000/init/default/json_read_nologin?email=user%40domain.com
http://localhost:8000/init/default/json_read_nologin/dXNlckBkb21haW4uY29tCg

web2py objects to the first, but not the second (vars) or third
(base64), both of which include 'encoded characters'.

Alex Fanjul

unread,
Jul 17, 2009, 11:26:34 PM7/17/09
to web...@googlegroups.com
Massimo, I think I'm getting some error like the David's one

I can't construct a dinamic url with an anchor with this sentence:
"URL(r=request,args="%s#anchor"%request.args[0])"

because web2py transform to:
"...default/proyecto/1%23anchor"

and it says "Invalid Request"

Any shortcut? or a way to encode/decode de "#" char?

Thanks,
Alex F
--
Alejandro Fanjul Fdez.
alex....@gmail.com
www.mhproject.org

Alex Fanjul

unread,
Jul 17, 2009, 11:30:21 PM7/17/09
to web...@googlegroups.com
Ok, I got it like this:
'_next':"%s#anchor"%URL(r=request,args=request.args[0])

Thanks

mdipierro

unread,
Jul 17, 2009, 11:41:59 PM7/17/09
to web2py-users
Or

'_next':URL(r=request,args=request.args[0],anchor='anchor')
> >>http://localhost:8000/init/default/json_read_nologin?email=user%40dom...
> >>http://localhost:8000/init/default/json_read_nologin/dXNlckBkb21haW4u...
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages