3 # Copyright 2008 the Melange authors.
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 """Access control helper.
19 The functions in this module can be used to check access control
20 related requirements. When the specified required conditions are not
21 met, an exception is raised. This exception contains a views that
22 either prompts for authentication, or informs the user that they
23 do not meet the required criteria.
27 '"Todd Larsen" <tlarsen@google.com>',
28 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
29 '"Pawel Solyga" <pawel.solyga@gmail.com>',
33 from google
.appengine
.api
import users
35 from django
.utils
.translation
import ugettext_lazy
37 from soc
.logic
import accounts
38 from soc
.logic
.models
import host
as host_logic
39 from soc
.logic
.models
import user
as user_logic
40 from soc
.logic
.models
import request
as request_logic
41 from soc
.views
import helper
42 from soc
.views
import out_of_band
45 DEF_NO_USER_LOGIN_MSG_FMT
= ugettext_lazy(
46 'Please create <a href="/user/edit">User Profile</a>'
47 ' in order to view this page.')
49 DEF_DEV_LOGOUT_LOGIN_MSG_FMT
= ugettext_lazy(
50 'Please <a href="%%(sign_out)s">sign out</a>'
51 ' and <a href="%%(sign_in)s">sign in</a>'
52 ' again as %(role)s to view this page.')
54 DEF_PAGE_DENIED_MSG
= ugettext_lazy(
55 'Access to this page has been restricted')
57 DEF_LOGOUT_MSG_FMT
= ugettext_lazy(
58 'Please <a href="%(sign_out)s">sign out</a> in order to view this page')
61 def checkAccess(access_type
, request
, rights
):
62 """Runs all the defined checks for the specified type.
65 access_type: the type of request (such as 'list' or 'edit')
66 request: the Django request object
67 rights: a dictionary containing access check functions
70 The rights dictionary is used to check if the current user is allowed
71 to view the page specified. The functions defined in this dictionary
72 are always called with the django request object as argument. On any
73 request, regardless of what type, the functions in the 'any_access' value
74 are called. If the specified type is not in the rights dictionary, all
75 the functions in the 'unspecified' value are called. When the specified
76 type _is_ in the rights dictionary, all the functions in that access_type's
80 True: If all the required access checks have been made successfully
81 False: If a check failed, in this case self._response will contain
82 the response provided by the failed access check.
85 # Call each access checker
86 for check
in rights
['any_access']:
89 if access_type
not in rights
:
90 for check
in rights
['unspecified']:
91 # No checks defined, so do the 'generic' checks and bail out
95 for check
in rights
[access_type
]:
100 """Never returns an alternate HTTP response.
103 request: a Django HTTP request
109 """Returns an alternate HTTP response.
112 request: a Django HTTP request
115 a subclass of django.http.HttpResponse which contains the
116 alternate response that should be returned by the calling view.
120 context
['title'] = 'Access denied'
122 raise out_of_band
.AccessViolation(DEF_PAGE_DENIED_MSG
, context
=context
)
125 def checkIsLoggedIn(request
):
126 """Returns an alternate HTTP response if Google Account is not logged in.
129 request: a Django HTTP request
132 AccessViolationResponse: if the required authorization is not met
135 None if the user is logged in, or a subclass of
136 django.http.HttpResponse which contains the alternate response
137 that should be returned by the calling view.
140 if users
.get_current_user():
143 raise out_of_band
.LoginRequest()
146 def checkNotLoggedIn(request
):
147 """Returns an alternate HTTP response if Google Account is not logged in.
150 request: a Django HTTP request
153 AccessViolationResponse: if the required authorization is not met
156 None if the user is logged in, or a subclass of
157 django.http.HttpResponse which contains the alternate response
158 that should be returned by the calling view.
161 if not users
.get_current_user():
164 raise out_of_band
.LoginRequest(message_fmt
=DEF_LOGOUT_MSG_FMT
)
167 def checkIsUser(request
):
168 """Returns an alternate HTTP response if Google Account has no User entity.
171 request: a Django HTTP request
174 AccessViolationResponse: if the required authorization is not met
177 None if User exists for a Google Account, or a subclass of
178 django.http.HttpResponse which contains the alternate response
179 should be returned by the calling view.
182 checkIsLoggedIn(request
)
184 user
= user_logic
.logic
.getForFields(
185 {'account': users
.get_current_user()}, unique
=True)
190 raise out_of_band
.LoginRequest(message_fmt
=DEF_NO_USER_LOGIN_MSG_FMT
)
193 def checkIsDeveloper(request
):
194 """Returns an alternate HTTP response if Google Account is not a Developer.
197 request: a Django HTTP request
200 AccessViolationResponse: if the required authorization is not met
203 None if Google Account is logged in and logged-in user is a Developer,
204 or a subclass of django.http.HttpResponse which contains the alternate
205 response should be returned by the calling view.
210 if accounts
.isDeveloper(account
=users
.get_current_user()):
213 login_message_fmt
= DEF_DEV_LOGOUT_LOGIN_MSG_FMT
% {
214 'role': 'a site developer '}
216 raise out_of_band
.LoginRequest(message_fmt
=login_message_fmt
)
219 def checkIsHost(request
):
220 """Returns an alternate HTTP response if Google Account has no Host entity
221 for the specified program.
224 request: a Django HTTP request
227 AccessViolationResponse: if the required authorization is not met
230 None if Host exists for the specified program, or a subclass of
231 django.http.HttpResponse which contains the alternate response
232 should be returned by the calling view.
236 # if the current user is a developer we allow access
237 checkIsInvited(request
)
239 except out_of_band
.Error
:
244 user
= user_logic
.logic
.getForFields(
245 {'account': users
.get_current_user()}, unique
=True)
247 host
= host_logic
.logic
.getForFields(
248 {'user': user
}, unique
=True)
253 login_message_fmt
= DEF_DEV_LOGOUT_LOGIN_MSG_FMT
% {
256 raise out_of_band
.LoginRequest(message_fmt
=login_message_fmt
)
259 def checkIsInvited(request
):
260 """Returns an alternate HTTP response if Google Account has no Host entity
261 for the specified program.
264 request: a Django HTTP request
267 AccessViolationResponse: if the required authorization is not met
270 None if Host exists for the specified program, or a subclass of
271 django.http.HttpResponse which contains the alternate response
272 should be returned by the calling view.
276 # if the current user is a developer we allow access
277 checkIsDeveloper(request
)
279 except out_of_band
.Error
:
284 login_message_fmt
= DEF_DEV_LOGOUT_LOGIN_MSG_FMT
% {
285 'role': 'a host for this program'}
287 splitpath
= request
.path
.split('/')
288 splitpath
= splitpath
[1:] # cut off leading ''
290 if len(splitpath
) < 4:
291 # TODO: perhaps this needs a better explanation?
295 group_id
= splitpath
[2]
296 user_id
= splitpath
[3]
298 user
= user_logic
.logic
.getForFields(
299 {'account': users
.get_current_user()}, unique
=True)
301 if user_id
!= user
.link_id
:
302 # TODO: perhaps this needs a better explanation?
308 'scope_path': group_id
,
309 'group_accepted': True,
312 request
= request_logic
.logic
.getForFields(properties
, unique
=True)
317 raise out_of_band
.LoginRequest(message_fmt
=login_message_fmt
)
320 def checkIsDocumentPublic(request
):
321 """Checks whether a document is public
324 request: a Django HTTP request
327 # TODO: A proper check needs to be done to see if the document
328 # is public or not, probably involving analysing it's scope or such.