Skip to content

Commit

Permalink
Adapt sso_login for ajax POST
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-morvan committed Nov 14, 2017
1 parent a37f3ea commit f1ac7d6
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 42 deletions.
51 changes: 36 additions & 15 deletions c2corg_api/tests/views/test_sso.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,20 +340,39 @@ def setUp(self):
self.session.flush()

def test_no_token(self):
self.app.get(self._url, status=403)
body = self.app_post_json(self._url, status=400).json
errors = body.get('errors')
self.assertEqual('token', errors[0].get('name'))
self.assertEqual('Required', errors[0].get('description'))

def test_invalid_token(self):
self.app.get(self._url,
params={'token': 'bad_token'},
status=403)
body = self.app_post_json(self._url,
{'token': 'bad_token'},
status=403).json
errors = body.get('errors')
self.assertEqual('token', errors[0].get('name'))
self.assertEqual('Invalid', errors[0].get('description'))

def test_expired_token(self):
self.sso_external_id.expire = localized_now()
self.session.flush()

self.app.get(self._url,
params={'token': 'good_token'},
status=403)
body = self.app_post_json(self._url,
params={'token': 'good_token'},
status=403).json
errors = body.get('errors')
self.assertEqual('token', errors[0].get('name'))
self.assertEqual('Invalid', errors[0].get('description'))

def test_success(self):
self.sso_external_id.expire = sso_expire_from_now()
self.session.flush()

body = self.app_post_json(self._url,
{'discourse': True,
'token': 'good_token'},
status=200).json
self.assertTrue('token' in body)

@patch(
'c2corg_api.views.sso.get_discourse_client',
Expand All @@ -367,11 +386,11 @@ def test_success_discourse_up(self, discourse_mock):
self.sso_external_id.expire = sso_expire_from_now()
self.session.flush()

r = self.app.get(self._url,
params={'token': 'good_token'},
status=302)

self.assertEqual('https://discourse_redirect', r.location)
body = self.app_post_json(self._url,
{'discourse': True,
'token': 'good_token'},
status=200).json
self.assertTrue('token' in body)

@patch(
'c2corg_api.views.sso.get_discourse_client',
Expand All @@ -384,6 +403,8 @@ def test_success_discourse_down(self, discourse_mock):
self.sso_external_id.expire = sso_expire_from_now()
self.session.flush()

self.app.get(self._url,
params={'token': 'good_token'},
status=200)
body = self.app_post_json(self._url,
{'discourse': True,
'token': 'good_token'},
status=200).json
self.assertTrue('token' in body)
60 changes: 33 additions & 27 deletions c2corg_api/views/sso.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
from cornice.validators import colander_body_validator
from pydiscourse.exceptions import DiscourseClientError
from pyramid.httpexceptions import (
HTTPForbidden,
HTTPFound,
HTTPInternalServerError,
)

Expand All @@ -32,6 +30,7 @@
json_view,
)
from c2corg_api.views.user import (
token_to_response,
validate_unique_attribute,
validate_forum_username,
)
Expand Down Expand Up @@ -204,8 +203,9 @@ def post(self):
group_id, discourse_userid)

return {
'url': '{}?{}'.format(request.route_url('ssologinrest'),
urlencode({'token': sso_external_id.token}))
'url': '{}/sso-login?no_redirect&{}'.format(
request.registry.settings['ui.url'],
urlencode({'token': sso_external_id.token}))
}


Expand Down Expand Up @@ -239,21 +239,26 @@ def sso_expire_from_now():
return (localized_now() + timedelta(minutes=CONST_EXPIRE_AFTER_MINUTES))


class SsoLoginSchema(colander.MappingSchema):
token = colander.SchemaNode(colander.String())

sso_login_schema = SsoLoginSchema()


def validate_token(request, **kwargs):
token = request.params.get('token', None)
if token is None:
log.warning('Attempt to use sso_login without token from {}'
.format(request.client_addr))
raise HTTPForbidden('Invalid token')
if 'token' not in request.validated:
return # validated by colander schema

sso_external_id = DBSession.query(SsoExternalId). \
filter(SsoExternalId.token == token). \
filter(SsoExternalId.token == request.validated['token']). \
filter(SsoExternalId.expire > localized_now()). \
one_or_none()
if sso_external_id is None:
log.warning('Attempt to use sso_login with bad token from {}'
.format(request.client_addr))
raise HTTPForbidden('Invalid token')
request.errors.status = 403
request.errors.add('body', 'token', 'Invalid')
return
request.validated['sso_user'] = sso_external_id.user


Expand All @@ -262,20 +267,21 @@ class SsoLoginRest(object):
def __init__(self, request):
self.request = request

@view(validators=[validate_token])
def get(self):
@view(
schema=sso_login_schema,
validators=[colander_body_validator, validate_token])
def post(self):
user = self.request.validated['sso_user']
log_validated_user_i_know_what_i_do(user, self.request)
client = get_discourse_client(self.request.registry.settings)
try:
r = client.redirect_without_nonce(user)
except:
# Any error with discourse should not prevent login
log.warning(
'Error logging into discourse for %d', user.id,
exc_info=True)
else:
return HTTPFound(r)
return {
'success': True
}
token = log_validated_user_i_know_what_i_do(user, self.request)
response = token_to_response(user, token, self.request)
if 'discourse' in self.request.json:
client = get_discourse_client(self.request.registry.settings)
try:
r = client.redirect_without_nonce(user)
response['redirect_internal'] = r
except:
# Any error with discourse should not prevent login
log.warning(
'Error logging into discourse for %d', user.id,
exc_info=True)
return response
2 changes: 2 additions & 0 deletions common.ini.in
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ discourse.api_key = {discourse_api_key}
discourse.sso_secret = {discourse_sso_secret}
discourse.category = {discourse_category}

ui.url = {ui_url}

mail.validate_register_url_template = {mail_validate_register_url_template}
mail.request_password_change_url_template = {mail_request_password_change_url_template}
mail.validate_change_email_url_template = {mail_validate_change_email_url_template}
Expand Down

0 comments on commit f1ac7d6

Please sign in to comment.