Copterfly / modwsgi

Automatically exported from code.google.com/p/modwsgi
0 stars 0 forks source link

WSGIAuthGroupScript not working, require directives present and no Authoritative handler #47

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. compile mod_wsgi 2.0c4 with apache 2.2.6
2. setup:
   AuthType Basic
   AuthName "Top Secret"
   AuthBasicProvider wsgi
   WSGIAuthUserScript /usr/local/hacr/etc/apache2/auth.wsgi
   WSGIAuthGroupScript /usr/local/hacr/etc/apache2/auth.wsgi
   require group secret-agents

with:

def groups_for_user(environ, user):
    if user == 'robrien':
        return ['secret-agents']
    return ['']

3. try to connect:

and I have tried with the following in 4 combinations (on/off, off/on,
on/on, off/off) to no avail:

   AuthzDefaultAuthoritative Off
   AuthzUserAuthoritative Off

What is the expected output? 

Login succeed

What do you see instead?

access to /trac/test/login failed, reason: require directives present and
no Authoritative handler., referer: https://localhost/trac

What version of the product are you using? On what operating system?

mod_wsgi 2.0c4
apache 2.2.6
RHEL 5/Mac OSX 10.4.11
python 2.5.1

Please provide any additional information below.

Dec 19 01:22:41 mack auth.wsgi: Auth attempt by: robrien
Dec 19 01:22:41 mack auth.wsgi: Got None robrien
Dec 19 01:22:41 mack auth.wsgi: checkCache: got robrien
Dec 19 01:22:41 mack auth.wsgi: robrien expired: False
Dec 19 01:22:41 mack auth.wsgi: robrien authenticated successfully
Dec 19 01:22:41 mack auth.wsgi: [error] [client ::1] access to
/trac/test/login failed, reason: require directives present and no
Authoritative handler., referer: https://localhost/trac/test

Original issue reported on code.google.com by reedobrien on 19 Dec 2007 at 6:27

GoogleCodeExporter commented 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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
:(

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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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