3 # Copyright 2005 Branko Cibej <brane@xbc.nu>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 '''mod_python authorization handler for mod_authz_svn groups.
19 This handler reads group definitions from a mod_authz_svn access
20 configuration file and does an authz check against that information.
22 Supported Require directives:
25 Checks if the authenticated user is mentioned in any of the groups.
26 Note that this is authorization, not authentication; so, a user may
27 have been authenticated correctly, yet still fail this test if
28 she is not mentioned in the authz config file.
30 - Require group name...
31 Check if the authenticated user is a member of any of the named
34 - Require user name...
35 Ignored. The authentication handlers are supposed to check this.
40 PythonAuthzHandler authz_svn_group
41 PythonOption AuthzSVNGroupFile /path/to/file
42 PythonOption AuthzSVNGroupAuthoritative Yes/On/1|No/Off/0
46 AuthzSVNGroupFile: Path to the mod_authz_svn configuration file.
47 AuthzSVNGroupAuthoritative: If turned off, authz_svn_group.py will
48 return DECLINED rather than HTTP_FORBIDDEN if a Require
49 directive is not satisfied.
54 from mod_python
import apache
57 '''Encapsulation of group info from the mod_authz_svn access file.'''
59 def __init__(self
, authz_file
):
60 '''Parse the SVN access file.'''
63 cfg
= ConfigParser
.ConfigParser()
65 if cfg
.has_section('groups'):
66 self
.__init
_groups
(cfg
)
68 def __init_groups(self
, cfg
):
69 '''Compute user and group membership.'''
70 group_list
= cfg
.options('groups')
72 for group
in group_list
:
73 names
= map(lambda x
: x
.strip(),
74 cfg
.get('groups', group
).split(','))
75 group_map
[group
] = names
77 if not name
.startswith('@'):
78 self
.__users
[name
] = None
79 for group
in group_list
:
80 self
.__groups
[group
] = self
.__expand
_group
_users
(group
, group_map
)
82 def __expand_group_users(self
, group
, group_map
):
83 '''Return the complete (recursive) list of users that belong to
84 a particular group, as a map.'''
86 for name
in group_map
[group
]:
87 if not name
.startswith('@'):
90 users
.update(self
.__expand
_group
_users
(name
[1:], group_map
))
93 def is_valid_user(self
, user
):
94 '''Return True if the user is valid.'''
95 return self
.__users
.has_key(user
)
97 def is_user_in_group(self
, user
, group
):
98 '''Return True if the user is in a particular group.'''
99 return (self
.__groups
.has_key(group
)
100 and self
.__groups
[group
].has_key(user
))
104 '''Handler configuration'''
106 AUTHZ_FILE
= 'AuthzSVNGroupFile'
107 AUTHORITATIVE
= 'AuthzSVNGroupAuthoritative'
109 def __init__(self
, req
):
110 self
.__authz
_file
= None
111 self
.__authoritative
= True
112 cfg
= req
.get_options()
114 if cfg
.has_key(self
.AUTHZ_FILE
):
115 self
.__authz
_file
= cfg
[self
.AUTHZ_FILE
]
116 if not os
.path
.exists(self
.__authz
_file
):
117 req
.log_error(('%s: "%s" not found'
118 % (self
.AUTHZ_FILE
, self
.__authz
_file
)),
120 raise apache
.SERVER_RETURN
, apache
.HTTP_INTERNAL_SERVER_ERROR
122 if cfg
.has_key(self
.AUTHORITATIVE
):
123 authcfg
= cfg
[self
.AUTHORITATIVE
].lower()
124 if authcfg
in ['yes', 'on', '1']:
125 self
.__authoritative
= True
126 elif authcfg
in ['no', 'off', '0']:
127 self
.__authoritative
= False
129 req
.log_error(('%s: invalid value "%s"'
130 % (self
.AUTHORITATIVE
, cfg
[self
.AUTHORITATIVE
])),
132 raise apache
.SERVER_RETURN
, apache
.HTTP_INTERNAL_SERVER_ERROR
135 def authz_file(self
):
136 return self
.__authz
_file
138 def authoritative(self
):
139 return self
.__authoritative
142 def __init_authz_info(req
, cfg
):
143 '''Initialize the global authz info if it is not available yet.
144 Return False if this module is disabled.'''
145 if not globals().has_key('__authz_svn_group_info'):
146 if cfg
.authz_file() is None:
148 global __authz_svn_group_info
149 __authz_svn_group_info
= __authz_info(cfg
.authz_file())
153 def authzhandler(req
):
154 '''The authorization handler.'''
156 if not __init_authz_info(req
, cfg
):
157 return apache
.DECLINED
159 if cfg
.authoritative():
160 forbidden
= apache
.HTTP_FORBIDDEN
162 forbidden
= apache
.DECLINED
164 req
.get_basic_auth_pw()
165 for requires
in req
.requires():
166 if requires
== 'valid-user':
167 if not __authz_svn_group_info
.is_valid_user(req
.user
):
169 elif requires
.startswith('group '):
170 for group
in requires
.split()[1:]:
171 if __authz_svn_group_info
.is_user_in_group(req
.user
, group
):
175 elif requires
.startswith('user '):
176 pass # Handled by the authen handler
178 req
.log_error('Unknown directive "Require %s"' % requires
,
180 return apache
.HTTP_INTERNAL_SERVER_ERROR