Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Fix fallback auth on Python 3 #4197

Merged
merged 3 commits into from
Nov 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/4197.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fallback auth now accepts the session parameter on Python 3.
38 changes: 16 additions & 22 deletions synapse/rest/client/v2_alpha/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from synapse.api.errors import SynapseError
from synapse.api.urls import CLIENT_V2_ALPHA_PREFIX
from synapse.http.server import finish_request
from synapse.http.servlet import RestServlet
from synapse.http.servlet import RestServlet, parse_string

from ._base import client_v2_patterns

Expand Down Expand Up @@ -131,16 +131,12 @@ def __init__(self, hs):
self.auth_handler = hs.get_auth_handler()
self.registration_handler = hs.get_handlers().registration_handler

@defer.inlineCallbacks
def on_GET(self, request, stagetype):
yield
if stagetype == LoginType.RECAPTCHA:
if ('session' not in request.args or
len(request.args['session']) == 0):
raise SynapseError(400, "No session supplied")

session = request.args["session"][0]
session = parse_string(request, "session")
if not session:
raise SynapseError(400, "No session supplied")

if stagetype == LoginType.RECAPTCHA:
html = RECAPTCHA_TEMPLATE % {
'session': session,
'myurl': "%s/auth/%s/fallback/web" % (
Expand All @@ -155,10 +151,8 @@ def on_GET(self, request, stagetype):

request.write(html_bytes)
finish_request(request)
defer.returnValue(None)
return None
elif stagetype == LoginType.TERMS:
session = request.args['session'][0]

html = TERMS_TEMPLATE % {
'session': session,
'terms_url': "%s/_matrix/consent?v=%s" % (
Expand All @@ -176,25 +170,25 @@ def on_GET(self, request, stagetype):

request.write(html_bytes)
finish_request(request)
defer.returnValue(None)
return None
else:
raise SynapseError(404, "Unknown auth stage type")

@defer.inlineCallbacks
def on_POST(self, request, stagetype):
yield

session = parse_string(request, "session")
if not session:
raise SynapseError(400, "No session supplied")

if stagetype == LoginType.RECAPTCHA:
if ('g-recaptcha-response' not in request.args or
len(request.args['g-recaptcha-response'])) == 0:
raise SynapseError(400, "No captcha response supplied")
if ('session' not in request.args or
len(request.args['session'])) == 0:
raise SynapseError(400, "No session supplied")
response = parse_string(request, "g-recaptcha-response")

session = request.args['session'][0]
if not response:
raise SynapseError(400, "No captcha response supplied")

authdict = {
'response': request.args['g-recaptcha-response'][0],
'response': response,
'session': session,
}

Expand Down
104 changes: 104 additions & 0 deletions tests/rest/client/v2_alpha/test_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# Copyright 2018 New Vector
#
# 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.


from twisted.internet.defer import succeed

from synapse.api.constants import LoginType
from synapse.rest.client.v1 import admin
from synapse.rest.client.v2_alpha import auth, register

from tests import unittest


class FallbackAuthTests(unittest.HomeserverTestCase):

servlets = [
auth.register_servlets,
admin.register_servlets,
register.register_servlets,
]
hijack_auth = False

def make_homeserver(self, reactor, clock):

config = self.default_config()

config.enable_registration_captcha = True
config.recaptcha_public_key = "brokencake"
config.registrations_require_3pid = []

hs = self.setup_test_homeserver(config=config)
return hs

def prepare(self, reactor, clock, hs):
auth_handler = hs.get_auth_handler()

self.recaptcha_attempts = []

def _recaptcha(authdict, clientip):
self.recaptcha_attempts.append((authdict, clientip))
return succeed(True)

auth_handler.checkers[LoginType.RECAPTCHA] = _recaptcha

@unittest.INFO
def test_fallback_captcha(self):

request, channel = self.make_request(
"POST",
"register",
{"username": "user", "type": "m.login.password", "password": "bar"},
)
self.render(request)

# Returns a 401 as per the spec
self.assertEqual(request.code, 401)
# Grab the session
session = channel.json_body["session"]
# Assert our configured public key is being given
self.assertEqual(
channel.json_body["params"]["m.login.recaptcha"]["public_key"], "brokencake"
)

request, channel = self.make_request(
"GET", "auth/m.login.recaptcha/fallback/web?session=" + session
)
self.render(request)
self.assertEqual(request.code, 200)

request, channel = self.make_request(
"POST",
"auth/m.login.recaptcha/fallback/web?session="
+ session
+ "&g-recaptcha-response=a",
)
self.render(request)
self.assertEqual(request.code, 200)

# The recaptcha handler is called with the response given
self.assertEqual(len(self.recaptcha_attempts), 1)
self.assertEqual(self.recaptcha_attempts[0][0]["response"], "a")

# Now we have fufilled the recaptcha fallback step, we can then send a
# request to the register API with the session in the authdict.
request, channel = self.make_request(
"POST", "register", {"auth": {"session": session}}
)
self.render(request)
self.assertEqual(channel.code, 200)

# We're given a registered user.
self.assertEqual(channel.json_body["user_id"], "@user:test")