1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
#!/usr/bin/python
#
# Copyright 2005 Branko Cibej <brane@xbc.nu>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
'''mod_python authorization handler for mod_authz_svn groups.
This handler reads group definitions from a mod_authz_svn access
configuration file and does an authz check against that information.
Supported Require directives:
- Require valid-user
Checks if the authenticated user is mentioned in any of the groups.
Note that this is authorization, not authentication; so, a user may
have been authenticated correctly, yet still fail this test if
she is not mentioned in the authz config file.
- Require group name...
Check if the authenticated user is a member of any of the named
groups.
- Require user name...
Ignored. The authentication handlers are supposed to check this.
Configuration:
<Location ...>
PythonAuthzHandler authz_svn_group
PythonOption AuthzSVNGroupFile /path/to/file
PythonOption AuthzSVNGroupAuthoritative Yes/On/1|No/Off/0
...
</Location>
AuthzSVNGroupFile: Path to the mod_authz_svn configuration file.
AuthzSVNGroupAuthoritative: If turned off, authz_svn_group.py will
return DECLINED rather than HTTP_FORBIDDEN if a Require
directive is not satisfied.
'''
import os, sys
import ConfigParser
from mod_python import apache
class __authz_info:
'''Encapsulation of group info from the mod_authz_svn access file.'''
def __init__(self, authz_file):
'''Parse the SVN access file.'''
self.__groups = {}
self.__users = {}
cfg = ConfigParser.ConfigParser()
cfg.read(authz_file)
if cfg.has_section('groups'):
self.__init_groups(cfg)
def __init_groups(self, cfg):
'''Compute user and group membership.'''
group_list = cfg.options('groups')
group_map = {}
for group in group_list:
names = map(lambda x: x.strip(),
cfg.get('groups', group).split(','))
group_map[group] = names
for name in names:
if not name.startswith('@'):
self.__users[name] = None
for group in group_list:
self.__groups[group] = self.__expand_group_users(group, group_map)
def __expand_group_users(self, group, group_map):
'''Return the complete (recursive) list of users that belong to
a particular group, as a map.'''
users = {}
for name in group_map[group]:
if not name.startswith('@'):
users[name] = None
else:
users.update(self.__expand_group_users(name[1:], group_map))
return users
def is_valid_user(self, user):
'''Return True if the user is valid.'''
return self.__users.has_key(user)
def is_user_in_group(self, user, group):
'''Return True if the user is in a particular group.'''
return (self.__groups.has_key(group)
and self.__groups[group].has_key(user))
class __config:
'''Handler configuration'''
AUTHZ_FILE = 'AuthzSVNGroupFile'
AUTHORITATIVE = 'AuthzSVNGroupAuthoritative'
def __init__(self, req):
self.__authz_file = None
self.__authoritative = True
cfg = req.get_options()
if cfg.has_key(self.AUTHZ_FILE):
self.__authz_file = cfg[self.AUTHZ_FILE]
if not os.path.exists(self.__authz_file):
req.log_error(('%s: "%s" not found'
% (self.AUTHZ_FILE, self.__authz_file)),
apache.APLOG_ERR)
raise apache.SERVER_RETURN, apache.HTTP_INTERNAL_SERVER_ERROR
if cfg.has_key(self.AUTHORITATIVE):
authcfg = cfg[self.AUTHORITATIVE].lower()
if authcfg in ['yes', 'on', '1']:
self.__authoritative = True
elif authcfg in ['no', 'off', '0']:
self.__authoritative = False
else:
req.log_error(('%s: invalid value "%s"'
% (self.AUTHORITATIVE, cfg[self.AUTHORITATIVE])),
apache.APLOG_ERR)
raise apache.SERVER_RETURN, apache.HTTP_INTERNAL_SERVER_ERROR
pass
def authz_file(self):
return self.__authz_file
def authoritative(self):
return self.__authoritative
def __init_authz_info(req, cfg):
'''Initialize the global authz info if it is not available yet.
Return False if this module is disabled.'''
if not globals().has_key('__authz_svn_group_info'):
if cfg.authz_file() is None:
return False
global __authz_svn_group_info
__authz_svn_group_info = __authz_info(cfg.authz_file())
return True
def authzhandler(req):
'''The authorization handler.'''
cfg = __config(req)
if not __init_authz_info(req, cfg):
return apache.DECLINED
if cfg.authoritative():
forbidden = apache.HTTP_FORBIDDEN
else:
forbidden = apache.DECLINED
req.get_basic_auth_pw()
for requires in req.requires():
if requires == 'valid-user':
if not __authz_svn_group_info.is_valid_user(req.user):
return forbidden
elif requires.startswith('group '):
for group in requires.split()[1:]:
if __authz_svn_group_info.is_user_in_group(req.user, group):
break
else:
return forbidden
elif requires.startswith('user '):
pass # Handled by the authen handler
else:
req.log_error('Unknown directive "Require %s"' % requires,
apache.APLOG_ERR)
return apache.HTTP_INTERNAL_SERVER_ERROR
return apache.OK
|