Closed GoogleCodeExporter closed 9 years ago
Add
require valid-user
after:
require group secret-agents
Left this out of recipe and is probably required.
Original comment by Graham.Dumpleton@gmail.com
on 19 Dec 2007 at 6:31
I found another thread you posted to that said soething about
require wsgi-group manager
so I put that in and it worked. Though it seems that should be pre 2.0c3 and I
am
using 2.0c4
Dec 19 01:35:50 mack auth.wsgi: robrien is in: Admin Manager
I will try require valid-user after require group secret-agents
Original comment by reedobrien
on 19 Dec 2007 at 6:38
I tried with:
require group secret-agents
require valid-user
And it let me in fine.
THen I changed to
require group goons
require valid-user
And althohugh I am not in goons it let me in anyhow
So I switched back to:
require wsgi-group goons #secret-agents
# require valid-user
And it didn't authorize.
Looks like wsgi-group is still the working directive?
Original comment by reedobrien
on 19 Dec 2007 at 6:44
The wsgi-group label is not mentioned in 2.0c4 source code anywhere, so can't
be that.
BTW, am not sure that # works as comment character at anywhere but start of
line in Apache configuration, so
having #secret-agents is probably meaning a group called that.
In your auth.wsgi file do you have a check_password() function?
I'll retest things to remind myself how it works and make sure example is
actually correct.
Original comment by Graham.Dumpleton@gmail.com
on 19 Dec 2007 at 6:53
:(
I updated my code and another machine to 2.0c4. This one is still running
2.0c3.
I'll update and get back to you.
Original comment by reedobrien
on 19 Dec 2007 at 7:06
I updated to 2.0c4 on this machine and it appears that none of the following
work:
Order deny,allow
Deny from all
Allow from all
AuthType basic
AuthBasicProvider wsgi
WSGIAuthUserScript /usr/local/hacr/etc/apache2/auth.wsgi
WSGIAuthGroupScript /usr/local/hacr/etc/apache2/auth.wsgi
require group Manager
require valid-user
Order deny,allow
Deny from all
Allow from all
AuthType basic
AuthBasicProvider wsgi
WSGIAuthUserScript /usr/local/hacr/etc/apache2/auth.wsgi
WSGIAuthGroupScript /usr/local/hacr/etc/apache2/auth.wsgi
require group Manager
Order deny,allow
Deny from all
Allow from all
AuthType basic
AuthBasicProvider wsgi
AuthName "HACR (test trac)"
WSGIAuthUserScript /usr/local/hacr/etc/apache2/auth.wsgi
WSGIAuthGroupScript /usr/local/hacr/etc/apache2/auth.wsgi
require wsgi-group Manager
Order deny,allow
Deny from all
Allow from all
AuthType basic
AuthBasicProvider wsgi
AuthName "HACR (test trac)"
WSGIAuthUserScript /usr/local/hacr/etc/apache2/auth.wsgi
WSGIAuthGroupScript /usr/local/hacr/etc/apache2/auth.wsgi
require group Manager
require valid-user
Nor with either or both AuthzUserAuthoritative AuthzDefaultAuthoritative Off
Original comment by reedobrien
on 19 Dec 2007 at 7:49
One wouldn't generally have both:
Deny from all
Allow from all
defined in the same context. Use just:
Allow from all
What do you have in auth.wsgi?
Do you have mod_authz_user and authz_default_module either statically compiled
or dynamically loaded into
your Apache instance?
If you set:
LogLevel info
do you see in Apache error log file that auth.wsgi is being loaded when a
request is made first time after
server restart.
If you add debug into check_password() and groups_for_user(), do you see in the
Apache error log file that the
functions are being called. Eg, add:
def check_password(environ, user, password):
print >> environ['wsgi.errors'], 'check_password ', user
...
def groups_for_user(environ, user):
print >> environ['wsgi.errors'], 'groups_for_user ', user
....
When you say it doesn't work, does the web browser at least popup a password
login prompt window? Better
describe what is happening and what HTTP error status is returned by the server
to the browser.
You should not be setting either AuthzUserAuthoritative or
AuthzDefaultAuthoritative. You want the default
values of On to be used.
Original comment by Graham.Dumpleton@gmail.com
on 19 Dec 2007 at 8:02
One wouldn't generally have both:
Deny from all
Allow from all
defined in the same context. Use just:
Allow from all
OK but this does work fine with authz_ldap_mod and basic
What do you have in auth.wsgi?
A lot. I will have to sanitize it to send it.
Do you have mod_authz_user and authz_default_module either statically compiled
or
dynamically loaded into
your Apache instance?
Yes
If you set:
LogLevel info
do you see in Apache error log file that auth.wsgi is being loaded when a
request is
made first time after
server restart.
Yes and I can see that the user authenticates, but then groups_for_user is never
called. Because of the require without Authoritative...
If you add debug into check_password() and groups_for_user(), do you see in the
Apache error log file that the
functions are being called. Eg, add:
def check_password(environ, user, password):
print >> environ['wsgi.errors'], 'check_password ', user
...
def groups_for_user(environ, user):
print >> environ['wsgi.errors'], 'groups_for_user ', user
....
See above yes for check_password, no for groups_for_user in 2.0c4
yes for both is I user wsgi-group in 2.0c3
When you say it doesn't work, does the web browser at least popup a password
login
prompt window? Better
describe what is happening and what HTTP error status is returned by the server
to
the browser.
Yes it prompts fine and accepts the input then dies with the above error
You should not be setting either AuthzUserAuthoritative or
AuthzDefaultAuthoritative.
You want the default
values of On to be used.
Ok, that was a desperate meaasure from some mod_python thread I think
Very tired. I will come back to this after sleep.
Original comment by reedobrien
on 19 Dec 2007 at 9:53
Do you set 'Satisfy' directive anywhere at all in your Apache configuration?
What other auth modules are loaded and have any of them been configured in a
context which would be
inherited by context that you are doing the WSGI stuff in?
Do you set the 'Require' directive in any other places in the Apache
configuration?
I thought I had worked out in the end that it was safe to use 'group' as label
to 'Require', but it is possible that
another auth module is interpreting before mod_wsgi gets a chance due to it
also being configured for that
context. If that is the case, then the other auth module has to be made to be
non authoritative. Thus, need to
know what other auth modules are loaded and configured.
Original comment by Graham.Dumpleton@gmail.com
on 19 Dec 2007 at 10:39
Do you set 'Satisfy' directive anywhere at all in your Apache configuration?
Yes:
<FilesMatch "^\.ht">
Order allow,deny
Deny from all
Satisfy All
</FilesMatch>
What other auth modules are loaded and have any of them been configured in a
context
which would be inherited by context that you are doing the WSGI stuff in?
authn_file_module (shared)
authn_dbm_module (shared)
authn_anon_module (shared)
authn_dbd_module (shared)
authn_default_module (shared)
authz_host_module (shared)
authz_groupfile_module (shared)
authz_user_module (shared)
authz_dbm_module (shared)
authz_owner_module (shared)
authnz_ldap_module (shared)
authz_default_module (shared)
auth_basic_module (shared)
auth_digest_module (shared)
Do you set the 'Require' directive in any other places in the Apache
configuration?
once for valid user and once for group, for two different Location directives
I thought I had worked out in the end that it was safe to use 'group' as label
to
'Require', but it is possible that another auth module is interpreting before
mod_wsgi gets a chance due to it also being configured for that context. If
that is
the case, then the other auth module has to be made to be non authoritative.
Thus,
need to know what other auth modules are loaded and configured.
Would you like more than the above? The complete list?
Here is a sanitized version of auth.wsgi:
#############################################
#$Id$
# Name: auth.wsgi
# Desc: provide Apache Authn service via
# WSGI as defined in:
#http://svn.apache.org/viewvc/httpd/httpd/tags/2.2.6/modules/aaa/mod_auth.h in
mod_auth.h
#http://modwsgi.googlecode.com/svn/tags/mod_wsgi-2.0c3/mod_wsgi.c
#
# Date: 2007-12-13
# Author: Reed L. O'Brien
#
#
##############################################
import sys
paths = [
'/usr/local/svn/src',
'/usr/local/svn/eggs/python_ldap-2.3.1-py2.5-macosx-10.3-i386.egg',
## TODO: Fix me so I am generated and don't have nonexistant paths
'/usr/local/svn/eggs/python_ldap-2.3.1-py2.5-linux-x86_64.egg'
]
for path in paths:
if path not in sys.path:
sys.path.append(path)
import bsddb, cPickle, hashlib
import kerberos, ldap, syslog, time
from random import choice
from kerberos import (BasicAuthError, GSSError, KrbError)
syslog.openlog('auth.wsgi', 0, syslog.LOG_AUTH)
## keep a cache so we don't beat up AD
## too much;)
# TODO: make this not hardwired
cache_location = '/usr/local/svn/var/apache/cache'
cache = bsddb.btopen(cache_location)
## set a timeout for cached items
cache_timeout = 1200
## Set the AD servers to bind to
ADs = [ 'pdc1.myco.com', 'bdc1.myco.com', 'dc2.nassa.com' ]
default_realm = 'MYCO.COM'
### a password for xmlrpcuser
### since this lookup is fastest it
### should be used for bulk imports
xmlrpcuser_pw_hash = 'secrethash'
def checkCache(environ, user, password):
try:
ce = cPickle.loads(cache[user])
syslog.syslog(syslog.LOG_DEBUG, "checkCache: got %s" % user)
assert ce.checkExpired() is False
syslog.syslog(syslog.LOG_DEBUG, "%s expired: %s" % (user, ce.checkExpired()))
if ce.checkPassword(password):
syslog.syslog(syslog.LOG_DEBUG, "%s expired: %s" % (user,
ce.checkPassword(password)))
return True
else:
return False
except AssertionError:
del cache[user]
syslog.syslog(syslog.LOG_DEBUG, "Expired %s from cache" % user)
return False
except KeyError:
syslog.syslog(syslog.LOG_DEBUG, "%s not in cache" % user)
return False
except:
raise
def addToCache(environ, user, password):
try:
ce = CacheEntry(password)
cache[user] = ce.dumps()
syslog.syslog(syslog.LOG_DEBUG, "Added %s to cache" % user)
except:
syslog.syslog(syslog.LOG_CRITICAL, "An error occured in auth.wsgi:addToCache")
raise
def checkAD(environ, user, password):
syslog.syslog(syslog.LOG_DEBUG, "Forwarding to AD")
try:
syslog.syslog(syslog.LOG_DEBUG, "Attempting to auth %s against AD" % user)
if kerberos.checkPassword(user, password, 'tgt/%s' % choice(ADs), default_realm):
return True
except (BasicAuthError, GSSError, KrbError), e:
syslog.syslog(syslog.LOG_INFO, "Auth error: %s %s" % (user, e))
return False
class CacheEntry(object):
def __init__(self, password):
"""Constructors"""
self.password = hashlib.sha224(password).hexdigest()
self.age = time.time()
def checkExpired(self):
"""Check if this entry is expired"""
if time.time() - self.age > cache_timeout:
return True
else:
return False
def checkPassword(self, password):
"""Check if password matches"""
if hashlib.sha224(password).hexdigest() == self.password:
return True
else:
return False
def dumps(self):
return cPickle.dumps(self)
def check_password(environ, user, password):
syslog.syslog(syslog.LOG_INFO, "Auth attempt by: %s" % user)
if '/' in user:
location, user = user.split('/')
else:
#user has no /
location = None
syslog.syslog(syslog.LOG_INFO, "Got %s %s" % (location, user))
### Now start looking for user
if (user == 'xmlrpcuser' and hashlib.sha224(password).hexdigest() ==
xmlrpcuser_pw_hash):
syslog.syslog(syslog.LOG_INFO, "Authenticated xmlrpcuser")
return True
if checkCache(environ, user, password):
return True
if checkAD(environ, user, password):
print >> environ['wsgi.errors'], "check_password User in AD adding to cache"
addToCache(environ, user, password)
return True
def groups_for_user(environ, user):
return ['Manager',]
dn = 'ou=groups,dc=svn,dc=myco,dc=com'
search_filter =
"(&(objectClass=groupOfUniqueNames)(uniqueMember=uid=%s,ou=people,dc=svn,dc=myco
,dc=com))"
% user
attrs = ['cn',]
try:
l = ldap.initialize('ldap://localhost')
l.search(dn, ldap.SCOPE_SUBTREE, search_filter, attrs)
res = l.result(1)
syslog.syslog(syslog.LOG_DEBUG, "%s is in: %s" % (user,
'\n\t'.join([x[1]['cn'][0] for x in res[1]])))
return [x[1]['cn'][0] for x in res[1]]
except:
raise
# TODO: figure out what to catch here and log
# then return the empty list
return ['']
def _test():
import doctest
doctest.testmod()
if __name__ == "__main__":
_test()
Original comment by reedobrien
on 25 Dec 2007 at 7:05
Can you ensure that you have set:
AuthzLDAPAuthoritative Off
for just the URL context that the mod_wsgi authorisation is being used.
The loading of the ldap module is the only difference I can see with the
modules loaded by my Apache on
MacOSX Leopard. If it is possible not to load the Apache LDAP module
altogether, that would also be a good
check.
Note, I am going to start up a discussion on the Google group for mod_wsgi to
see if I can get anyone else to
check at least that basic authn/authz with mod_wsgi works using these hooks.
Hopefully this will help to flush
out what it is in your configuration that is different causing it to not work
when work for me.
Original comment by Graham.Dumpleton@gmail.com
on 26 Dec 2007 at 1:58
Tried with:
AuthzLDAPAuthoritative Off
Also tried removing it from module load section. Additionally I reduced loads
to
authz_host_module (shared)
authz_default_module (shared)
auth_basic_module (shared)
with the same result:
Dec 25 23:58:31 Reed auth.wsgi: Auth attempt by: local/robrien
Dec 25 23:58:31 Reed auth.wsgi: [error] [client 127.0.0.1] access to /svn/test
failed, reason: require directives present and no Authoritative handler.
Original comment by reedobrien
on 26 Dec 2007 at 5:14
Can you modify mod_wsgi.c and at the start of:
wsgi_hook_auth_checker
after variable declarations add something like:
ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
"Attempt authorization of user '%s' to access '%s' .",
getpid(), r->user, r->uri);
Just verify whether the handler is even called at all.
It should be called on every request against the server.
Original comment by Graham.Dumpleton@gmail.com
on 26 Dec 2007 at 5:20
Done a logged attempt now looks like:
Dec 26 01:10:38 Reed httpd[14705]: [info] [client 127.0.0.1] mod_wsgi
(pid=14705,
process='', application=''): Loading WSGI script
'/usr/local/hacr/etc/apache2/auth.wsgi'.
Dec 26 01:10:38 Reed auth.wsgi: Auth attempt by: local/robrien
Dec 26 01:10:38 Reed auth.wsgi: Authenticated robrien
Dec 26 01:10:38 Reed auth.wsgi: [alert] [client 127.0.0.1] mod_wsgi (pid=14705):
Attempt authorization of user 'local/robrien' to access '/svn/test' .
Dec 26 01:10:38 Reed auth.wsgi: [error] [client 127.0.0.1] access to /svn/test
failed, reason: require directives present and no Authoritative handler.
Original comment by reedobrien
on 26 Dec 2007 at 6:12
Hmmm, interesting.
Can only suggest at this point to go through that same function and sprinkle
that debug in strategic places,
before and after return points etc, marking each as distinct and also printing
out stuff like the variable 'w' on
each iteration as Require directive is processed.
I'll look through the code, but possibly am pulling apart the Require directive
line incorrectly which for some
reason with your setup is causing problems.
Anyway, idea is if you can work out how far through that function it actually
gets before it tries to return and
with what return value it yields.
Thanks.
Original comment by Graham.Dumpleton@gmail.com
on 26 Dec 2007 at 6:44
I added a number of debug statements, but it doesn't seem to get very far in the
function. Log output below, and diff of added debugs after. In python of course
I'd
add pdb.set_trace() see where it was exiting. But I don't know how to get at a
loadable module from gdb:(
Dec 26 02:55:04 Reed httpd[19370]: [info] [client 127.0.0.1] mod_wsgi
(pid=19370,
process='', application=''): Loading WSGI script
'/usr/local/hacr/etc/apache2/auth.wsgi'.
Dec 26 02:55:04 Reed auth.wsgi: Auth attempt by: local/robrien
Dec 26 02:55:04 Reed auth.wsgi: Authenticated robrien
Dec 26 02:55:04 Reed auth.wsgi: [alert] [client 127.0.0.1] mod_wsgi (pid=19370):
Attempt authorization of user 'local/robrien' to access '/svn/test' .
Dec 26 02:55:04 Reed auth.wsgi: [alert] [client 127.0.0.1] mod_wsgi (pid=19370):
config: '\x806\x87\x01' for 'local/robrien'.
Dec 26 02:55:04 Reed auth.wsgi: [error] [client 127.0.0.1] access to /svn/test
failed, reason: require directives present and no Authoritative handler.
The sprinkling of debug logging was added as follows.
--- mod_wsgi.c 2007-12-26 07:32:38 +0000
+++ mod_wsgi.c 2007-12-26 07:56:16 +0000
@@ -10712,34 +10712,82 @@
apr_table_t *grpstatus = NULL;
char *reason = NULL;
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "Attempt authorization of user '%s' to access '%s' .",
+ getpid(), r->user, r->uri);
+
config = wsgi_create_req_config(r->pool, r);
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "config: '%s' for '%s'.",
+ getpid(), config->auth_group_script, r->user);
+
+
if (!config->auth_group_script)
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "!config->auth_group_script for user '%s' to access '%s'
.",
+ getpid(), config->auth_group_script, r->user);
+
return DECLINED;
+
+
reqs_arr = ap_requires(r);
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "reqs_arr: '%s' .",
+ getpid(), reqs_arr);
+
+
if (!reqs_arr)
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "!reqs_arr",
+ getpid());
+
return DECLINED;
reqs = (require_line *)reqs_arr->elts;
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "reqs: '%s' .",
+ getpid(), reqs);
+
for (x = 0; x < reqs_arr->nelts; x++) {
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "Made it to the for loop.",
+ getpid());
if (!(reqs[x].method_mask & (AP_METHOD_BIT << m))) {
continue;
}
t = reqs[x].requirement;
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "reqs: %s \n\nt:'%s' .",
+ getpid(), reqs, t);
+
w = ap_getword_white(r->pool, &t);
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "t: '%s' \n\nw:'%s' .",
+ getpid(), t, w);
if (!strcasecmp(w, "group")) {
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "!strcasecmp for w: '%s' .",
+ getpid(), w);
+
required_group = 1;
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d):
"
+ "required_group: '%d' .",
+ getpid(), required_group);
if (!grpstatus) {
int status;
status = wsgi_groups_for_user(r, config, &grpstatus);
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi
(pid=%d): "
+ "status '%d' .",
+ getpid(), status);
if (status != OK)
return status;
Original comment by reedobrien
on 26 Dec 2007 at 8:21
You can't have:
if (!config->auth_group_script)
+ ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
+ "!config->auth_group_script for user '%s' to access '%s'
.",
+ getpid(), config->auth_group_script, r->user);
+
return DECLINED;
as this is changing the logic. In C code indenting is not significant like
Python.
So, move any debug which you put in between the if() and return where there is
no braces, to before the if().
Ie., you want:
ap_log_rerror(APLOG_MARK, WSGI_LOG_ALERT(0), r, "mod_wsgi (pid=%d): "
"!config->auth_group_script for user '%s' to access '%s' .",
getpid(), config->auth_group_script, r->user);
if (!config->auth_group_script)
return DECLINED;
Original comment by Graham.Dumpleton@gmail.com
on 26 Dec 2007 at 8:33
I think it is working correctly here now. And I think I found the error
unsurprisingly not in your code, but my module.
I need sleep but will look again later today and make sure I am not hallucinating.
Original comment by reedobrien
on 26 Dec 2007 at 10:05
It appears to be working on this machine too. I will verify it on a clean
build over
the weekend and post what I was doing wrong:(
Original comment by reedobrien
on 28 Dec 2007 at 9:09
Presumed this was all resolved and is now working, so closing.
Original comment by Graham.Dumpleton@gmail.com
on 5 Jan 2008 at 2:25
Original issue reported on code.google.com by
reedobrien
on 19 Dec 2007 at 6:27