Re: [Zope-PAS] Cookie Auth Monopolizes Challenge?

2005-08-12 Thread Sidnei da Silva
On Thu, Aug 11, 2005 at 11:14:53PM -0300, Sidnei da Silva wrote:
| So my proposal would be to special-case the IChallengePlugin and let
| the site manager (or whatever title the person in charge of
| configuring PAS has) select which set of 'protocols' is allowed for
| each 'request type', where 'request type' would fall into 'browser,
| xml-rpc, webdav, ftp' but could be extended to support new
| request type. In fact, maybe this part could even be abstracted into a
| 'IRequestTypeSniffer' plugin.

So, here it is. I've implemented this idea and it has been checked
in. You can find it on the branch:

  sidnei-challenge-protocol-chooser

I've added a functional doctest to exemplify how it works:

http://cvs.zope.org/Products/PluggableAuthService/plugins/tests/Attic/ChallengeProtocolChooser.txt?rev=1.1.2.1&only_with_tag=sidnei-challenge-protocol-chooser

I would like to merge this branch early next week and make a new
release of PAS if everyone is fine with it (Remember: silence is
consent!) for inclusion on the next beta release of Enfold Server
which is scheduled for Wednesday, Aug 17.

-- 
Sidnei da Silva
Enfold Systems, LLC.
http://enfoldsystems.com
___
Zope-PAS mailing list
Zope-PAS@zope.org
http://mail.zope.org/mailman/listinfo/zope-pas


Re: [Zope-PAS] Cookie Auth Monopolizes Challenge?

2005-08-11 Thread Sidnei da Silva
On Fri, Aug 12, 2005 at 11:04:16AM +1000, Mark Hammond wrote:
|

|
| It sounds like the problem is that PAS does not have any concept of the
| "source" of the request.  The existing behaviour seems correct (enough) for
| the standard case of a web browser hitting the site on a standard HTTP
| port - but not for the other ways to get at the site.

That is straight to the point. After pondering for a little while,
I've came to the conclusion that all 'clients' should, for sanity
sake, use the exact same set of plugins, except for IChallengePlugin.

And the reason is because IChallengePlugin seems to be the only one
that actively 'changes the environment' in a way that might affect the
'client application'. All the other plugins are 'passive' client-wise,
that is they can be completely ignorant about the kind of request or
client being used to talk to Zope.

| What *might* be possible is something like the following untested patch,
| adapted from what Chris posted:
| 
| --- PluggableAuthService.py 27 May 2005 19:10:45 -  1.31
| +++ PluggableAuthService.py 12 Aug 2005 01:00:58 -
| @@ -990,7 +990,13 @@
|  plugins = self._getOb('plugins')
|  challengers = plugins.listPlugins( IChallengePlugin )
| 
| -protocol = None
| +if self.isDAVRequest(request):
| +# DAV clients/EE can't deal with form-based auth, so
| +# we insist on the http protocol
| +protocol = "http"
| +else:
| +# Other sources get anything that might be configured.
| +protocol = None
| 
|  for challenger_id, challenger in challengers:
|  challenger_protocol = getattr(challenger, 'protocol',

That looks pretty much like what I had in mind, except I wouldn't
hardcode the default protocol to 'http'.

| However, I assume the same concerns exist even when the request comes via
| xmlrpc, ftp, etc.  I'm not sure what to do about those cases.

I would say each different request type might only be compatible with
a set of protocols. I would go even further and say it's not even a
task for the plugin or for PAS to decide what protocol each request
type should use, but it should be a task for the site administrator.

An example: While I can't think of a existing WebDAV client that can
authenticate using say NTLM (maybe Windows Folders?), that doesn't
mean one can't create a it's own custom WebDAV client that *does* do
NTLM authentication (*hint* *hint* Mark?).

So my proposal would be to special-case the IChallengePlugin and let
the site manager (or whatever title the person in charge of
configuring PAS has) select which set of 'protocols' is allowed for
each 'request type', where 'request type' would fall into 'browser,
xml-rpc, webdav, ftp' but could be extended to support new
request type. In fact, maybe this part could even be abstracted into a
'IRequestTypeSniffer' plugin.

-- 
Sidnei da Silva
Enfold Systems, LLC.
http://enfoldsystems.com
___
Zope-PAS mailing list
Zope-PAS@zope.org
http://mail.zope.org/mailman/listinfo/zope-pas


RE: [Zope-PAS] Cookie Auth Monopolizes Challenge?

2005-08-11 Thread Mark Hammond
[Sid]

> So, leaving other issues aside *wink*, I'm no puzzled by the challenge
> code in PAS. It looks like there was some attempt at distinguishing
> challenging by some sort of 'protocol', but it leaves a lot to be
> desired, or I don't understand how it's supposed to work.

Probably both ;)

The discussion on this is a little spread out, but almost all threads at
http://mail.zope.org/pipermail/zope-pas/2004-October/thread.html relate to
it in some way.

> The problem I'm facing now is that using the Cookie Auth plugin
> effectively breaks WebDAV (and possibly FTP and XML-RPC), because as
> soon as the Cookie Auth plugin is hit on challenge, it does a redirect
> to the login form.

Yeah, that is by design IIUC.

The problem was that a cookie auth plugin wants to reponds to an
unauthorized exception by doing a redirect, but http auth wants to do it via
401.

IIRC, the basic flow was:
* via a little magic, PAS would arrange for an Unauthorized exception to
call the main PAS 'unauthorized' function.  That may be what Chris patched
in his previous mail.
* PAS would call all "challenge" plugins in the order they were defined.

PAS needs to call *all* plugins - it can not simply stop after it finds a
plugin that does something.  Consider HTTP basic and NTLM authentication -
*both* those plugins must be called, so both the www-authenticate headers
appear.  However, as soon as the cookie plugin is invoked, which does a
redirect, the challenges setup by the other plugins have been lost.

Thus, a "protocol" was invented.  The first plugin to set a protocol means
that protocol "wins".  All plugins that use www-authenticate use the same
prefix - so once initiated, an Unauthorized challenge will not get "trumped"
by a redirect.

> Changing the Cookie Auth to come after Basic Auth doesn't help either,
> as then instead of a browser client being directed to the login form
> it gets a basic auth dialog instead.

Yep - as above, that is by design.

> Is it possible that nobody noticed this yet? Or is it just me not
> getting enough sleep last night?

It sounds like the problem is that PAS does not have any concept of the
"source" of the request.  The existing behaviour seems correct (enough) for
the standard case of a web browser hitting the site on a standard HTTP
port - but not for the other ways to get at the site.

What *might* be possible is something like the following untested patch,
adapted from what Chris posted:

--- PluggableAuthService.py 27 May 2005 19:10:45 -  1.31
+++ PluggableAuthService.py 12 Aug 2005 01:00:58 -
@@ -990,7 +990,13 @@
 plugins = self._getOb('plugins')
 challengers = plugins.listPlugins( IChallengePlugin )

-protocol = None
+if self.isDAVRequest(request):
+# DAV clients/EE can't deal with form-based auth, so
+# we insist on the http protocol
+protocol = "http"
+else:
+# Other sources get anything that might be configured.
+protocol = None

 for challenger_id, challenger in challengers:
 challenger_protocol = getattr(challenger, 'protocol',

However, I assume the same concerns exist even when the request comes via
xmlrpc, ftp, etc.  I'm not sure what to do about those cases.

Also, the above patch will not work if someone wants something other than
http auth on their dav port.  eg, consider a site that is configured to not
use cookies or http, but their own custom auth scheme, and therefore with
its own protocol.  The above patch would kill their site as their existing,
working plugin would be excluded.  It would not be hard to handle that
though.

Hope that helped a little,

Mark

___
Zope-PAS mailing list
Zope-PAS@zope.org
http://mail.zope.org/mailman/listinfo/zope-pas


Re: [Zope-PAS] Cookie Auth Monopolizes Challenge?

2005-08-11 Thread Sidnei da Silva
On Thu, Aug 11, 2005 at 03:18:43PM -0400, Chris McDonough wrote:
| Hi Sidnei,
| 
| I had to deal with this at some point and I wrote a PAS multiplugin that
| implemented the "unauthorized" method (forget which interface that
| belongs to)... here it is along with a helper method to figure out if a
| request came from a DAV client:



Yes, that is what I would do too.

But isn't it odd that you have to do this in the first place? I would
say the challenge method of the PAS user folder is halfway there. In
fact is so close I can barely believe it doesn't work.

So my question really is:

Is this a bug in PAS that it doesn't do this even if it pretends to?
Or are people really expected to keep reinventing the wheel?

-- 
Sidnei da Silva
Enfold Systems, LLC.
http://enfoldsystems.com
___
Zope-PAS mailing list
Zope-PAS@zope.org
http://mail.zope.org/mailman/listinfo/zope-pas


Re: [Zope-PAS] Cookie Auth Monopolizes Challenge?

2005-08-11 Thread Chris McDonough
Hi Sidnei,

I had to deal with this at some point and I wrote a PAS multiplugin that
implemented the "unauthorized" method (forget which interface that
belongs to)... here it is along with a helper method to figure out if a
request came from a DAV client:


security.declarePublic('unauthorized')
def unauthorized(self):
""" Override cookieauthplugin unauthorized to deal properly
with DAV requests """
req = self.REQUEST
resp = req['RESPONSE']

# If we set the auth cookie before, delete it now.
if resp.cookies.has_key(self.cookie_name):
del resp.cookies[self.cookie_name]

if self.isDAVRequest(req):
# DAV clients/EE can't deal with form-based auth, so
# we give them a basic auth 401 response code
realm = resp.realm
if realm:
resp.addHeader('WWW-Authenticate',
   'basic realm="%s"' % realm)
m = "You are not authorized to access this resource."
if resp.debug_mode:
if resp._auth:
m = m + '\nUsername and password are not
correct.'
else:
m = m + '\nNo Authorization header found.'

resp.setBody(m, is_error=1)
resp.setStatus(401)
return 1

# Redirect if desired.
url = self.getLoginURL()
if url is not None:
came_from = req.get('came_from', None)

if came_from is None:
came_from = req.get('URL', '')
query = req.get('QUERY_STRING')
if query:
if not query.startswith('?'):
query = '?' + query
came_from = came_from + query
else:
# If came_from contains a value it means the user
# must be coming through here a second time
# Reasons could be typos when providing credentials
# or a redirect loop (see below)
req_url = req.get('URL', '')

if req_url and req_url == url:
# Oops... The login_form cannot be reached by the
user -
# it might be protected itself due to
misconfiguration -
# the only sane thing to do is to give up because we
are
# in an endless redirect loop.
return 0

url = url + '?came_from=%s' % quote(came_from)
resp.redirect(url, lock=1)
return 1

# Could not challenge.
return 0

security.declarePublic('isDAVRequest')
def isDAVRequest(self, request):
method = request.get('REQUEST_METHOD', 'GET')
if method in DAV_METHODS:
return True

if request.maybe_webdav_client and not method in ('GET',
'POST'):
return True

useragent = request.get_header('User-Agent') or ''
for agent in DAV_USERAGENTS:
if useragent.find(agent) != -1:
return True

return False



On Thu, 2005-08-11 at 15:46 -0300, Sidnei da Silva wrote:
> So, leaving other issues aside *wink*, I'm no puzzled by the challenge
> code in PAS. It looks like there was some attempt at distinguishing
> challenging by some sort of 'protocol', but it leaves a lot to be
> desired, or I don't understand how it's supposed to work.
> 
> The problem I'm facing now is that using the Cookie Auth plugin
> effectively breaks WebDAV (and possibly FTP and XML-RPC), because as
> soon as the Cookie Auth plugin is hit on challenge, it does a redirect
> to the login form.
> 
> Changing the Cookie Auth to come after Basic Auth doesn't help either,
> as then instead of a browser client being directed to the login form
> it gets a basic auth dialog instead.
> 
> Is it possible that nobody noticed this yet? Or is it just me not
> getting enough sleep last night?
> 

___
Zope-PAS mailing list
Zope-PAS@zope.org
http://mail.zope.org/mailman/listinfo/zope-pas