132 |
132 |
args.append(idp_message)
|
133 |
133 |
self.log.warning(*args)
|
134 |
134 |
|
|
135 |
def dispatch(self, request, *args, **kwargs):
|
|
136 |
try:
|
|
137 |
return super().dispatch(request, *args, **kwargs)
|
|
138 |
except utils.CreateServerError:
|
|
139 |
return self.failure(
|
|
140 |
request,
|
|
141 |
reason=_(
|
|
142 |
'Unable to initialize a SAML server object, the private key '
|
|
143 |
'is maybe invalid or unreadable, please check its access '
|
|
144 |
'rights and content.'
|
|
145 |
),
|
|
146 |
)
|
|
147 |
|
|
148 |
def failure(self, request, reason='', status_codes=()):
|
|
149 |
'''show error message to user after a login failure'''
|
|
150 |
login = self.profile
|
|
151 |
idp = utils.get_idp(login and login.remoteProviderId)
|
|
152 |
if not idp and login:
|
|
153 |
self.log.warning('entity id %r is unknown', login.remoteProviderId)
|
|
154 |
return HttpResponseBadRequest('entity id %r is unknown' % login.remoteProviderId)
|
|
155 |
error_url = utils.get_setting(idp, 'ERROR_URL')
|
|
156 |
error_redirect_after_timeout = utils.get_setting(idp, 'ERROR_REDIRECT_AFTER_TIMEOUT')
|
|
157 |
if error_url:
|
|
158 |
error_url = resolve_url(error_url)
|
|
159 |
next_url = error_url or self.get_next_url(default=resolve_url(settings.LOGIN_REDIRECT_URL))
|
|
160 |
return self.render(
|
|
161 |
request,
|
|
162 |
'mellon/authentication_failed.html',
|
|
163 |
{
|
|
164 |
'debug': settings.DEBUG,
|
|
165 |
'reason': reason,
|
|
166 |
'status_codes': status_codes,
|
|
167 |
'issuer': login and login.remoteProviderId,
|
|
168 |
'next_url': next_url,
|
|
169 |
'relaystate': login and login.msgRelayState,
|
|
170 |
'error_redirect_after_timeout': error_redirect_after_timeout,
|
|
171 |
},
|
|
172 |
)
|
|
173 |
|
135 |
174 |
|
136 |
175 |
class LoginView(ProfileMixin, LogMixin, View):
|
137 |
176 |
def dispatch(self, request, *args, **kwargs):
|
... | ... | |
197 |
236 |
if 'RelayState' in request.POST and utils.is_nonnull(request.POST['RelayState']):
|
198 |
237 |
login.msgRelayState = request.POST['RelayState']
|
199 |
238 |
return self.sso_success(request, login)
|
200 |
|
return self.sso_failure(request, reason=idp_message, status_codes=status_codes)
|
201 |
|
|
202 |
|
def sso_failure(self, request, reason='', status_codes=()):
|
203 |
|
'''show error message to user after a login failure'''
|
204 |
|
login = self.profile
|
205 |
|
idp = utils.get_idp(login.remoteProviderId)
|
206 |
|
if not idp:
|
207 |
|
self.log.warning('entity id %r is unknown', login.remoteProviderId)
|
208 |
|
return HttpResponseBadRequest('entity id %r is unknown' % login.remoteProviderId)
|
209 |
|
error_url = utils.get_setting(idp, 'ERROR_URL')
|
210 |
|
error_redirect_after_timeout = utils.get_setting(idp, 'ERROR_REDIRECT_AFTER_TIMEOUT')
|
211 |
|
if error_url:
|
212 |
|
error_url = resolve_url(error_url)
|
213 |
|
next_url = error_url or self.get_next_url(default=resolve_url(settings.LOGIN_REDIRECT_URL))
|
214 |
|
return self.render(
|
215 |
|
request,
|
216 |
|
'mellon/authentication_failed.html',
|
217 |
|
{
|
218 |
|
'debug': settings.DEBUG,
|
219 |
|
'reason': reason,
|
220 |
|
'status_codes': status_codes,
|
221 |
|
'issuer': login.remoteProviderId,
|
222 |
|
'next_url': next_url,
|
223 |
|
'relaystate': login.msgRelayState,
|
224 |
|
'error_redirect_after_timeout': error_redirect_after_timeout,
|
225 |
|
},
|
226 |
|
)
|
|
239 |
return self.failure(request, reason=idp_message, status_codes=status_codes)
|
227 |
240 |
|
228 |
241 |
def get_attribute_value(self, attribute, attribute_value):
|
229 |
242 |
# check attribute_value contains only text
|
... | ... | |
340 |
353 |
Use a cookie to prevent looping forever.
|
341 |
354 |
"""
|
342 |
355 |
if RETRY_LOGIN_COOKIE in self.request.COOKIES:
|
343 |
|
response = self.sso_failure(
|
|
356 |
response = self.failure(
|
344 |
357 |
self.request, reason=_('There were too many redirections with the identity provider.')
|
345 |
358 |
)
|
346 |
359 |
response.delete_cookie(RETRY_LOGIN_COOKIE)
|
... | ... | |
392 |
405 |
)
|
393 |
406 |
except RequestException as e:
|
394 |
407 |
self.log.warning('unable to reach %r: %s', login.msgUrl, e)
|
395 |
|
return self.sso_failure(
|
|
408 |
return self.failure(
|
396 |
409 |
request,
|
397 |
410 |
reason=_('IdP is temporarily down, please try again ' 'later.'),
|
398 |
411 |
status_codes=status_codes,
|
... | ... | |
403 |
416 |
result.status_code,
|
404 |
417 |
result.content,
|
405 |
418 |
)
|
406 |
|
return self.sso_failure(request, reason=idp_message, status_codes=status_codes)
|
|
419 |
return self.failure(request, reason=idp_message, status_codes=status_codes)
|
407 |
420 |
|
408 |
421 |
self.log.info('Got SAML Artifact Response', extra={'saml_response': result.content})
|
409 |
422 |
result.encoding = utils.get_xml_encoding(result.content)
|
... | ... | |
447 |
460 |
return HttpResponseBadRequest('error processing the authentication response: %r' % e)
|
448 |
461 |
else:
|
449 |
462 |
return self.sso_success(request, login)
|
450 |
|
return self.sso_failure(request, reason=idp_message, status_codes=status_codes)
|
|
463 |
return self.failure(request, reason=idp_message, status_codes=status_codes)
|
451 |
464 |
|
452 |
465 |
def request_discovery_service(self, request, is_passive=False):
|
453 |
466 |
return_url = request.build_absolute_uri()
|