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

Display an error during failure of fallback UIA #10561

Merged
merged 9 commits into from
Aug 18, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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/10561.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Handle failure of User-Interactive Authentication when using a fallback. Contributed by Callum Brown.
govynnus marked this conversation as resolved.
Show resolved Hide resolved
23 changes: 14 additions & 9 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,23 +627,28 @@ async def check_ui_auth(

async def add_oob_auth(
self, stagetype: str, authdict: Dict[str, Any], clientip: str
) -> bool:
) -> None:
"""
Adds the result of out-of-band authentication into an existing auth
session. Currently used for adding the result of fallback auth.

Raises:
LoginError if the stagetype is unknown or the session is missing.
LoginError is raised by check_auth if authentication fails.
"""
if stagetype not in self.checkers:
raise LoginError(400, "", Codes.MISSING_PARAM)
raise LoginError(
400, f"Unknown UIA stage type: {stagetype}", Codes.INVALID_PARAM
)
if "session" not in authdict:
raise LoginError(400, "", Codes.MISSING_PARAM)
raise LoginError(400, "Missing session ID", Codes.MISSING_PARAM)

# If authentication fails a LoginError is raised. Otherwise, store
# the successful result.
result = await self.checkers[stagetype].check_auth(authdict, clientip)
if result:
await self.store.mark_ui_auth_stage_complete(
authdict["session"], stagetype, result
)
return True
return False
await self.store.mark_ui_auth_stage_complete(
authdict["session"], stagetype, result
)

def get_session_id(self, clientdict: Dict[str, Any]) -> Optional[str]:
"""
Expand Down
2 changes: 1 addition & 1 deletion synapse/handlers/ui_auth/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ async def check_auth(self, authdict: dict, clientip: str) -> Any:
clientip: The IP address of the client.

Raises:
SynapseError if authentication failed
LoginError if authentication failed.

Returns:
The result of authentication (to pass back to the client?)
govynnus marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
3 changes: 3 additions & 0 deletions synapse/res/templates/recaptcha.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<body>
<form id="registrationForm" method="post" action="{{ myurl }}">
<div>
{% if error is defined %}
<p class="error"><strong>Error: {{ error }}</strong></p>
clokep marked this conversation as resolved.
Show resolved Hide resolved
{% endif %}
<p>
Hello! We need to prevent computer programs and other automated
things from creating accounts on this server.
Expand Down
3 changes: 3 additions & 0 deletions synapse/res/templates/terms.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
<body>
<form id="registrationForm" method="post" action="{{ myurl }}">
<div>
{% if error is defined %}
<p class="error"><strong>Error: {{ error }}</strong></p>
{% endif %}
<p>
Please click the button below if you agree to the
<a href="{{ terms_url }}">privacy policy of this homeserver.</a>
Expand Down
39 changes: 24 additions & 15 deletions synapse/rest/client/v2_alpha/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from typing import TYPE_CHECKING

from synapse.api.constants import LoginType
from synapse.api.errors import SynapseError
from synapse.api.errors import LoginError, SynapseError
from synapse.api.urls import CLIENT_API_PREFIX
from synapse.http.server import respond_with_html
from synapse.http.servlet import RestServlet, parse_string
Expand Down Expand Up @@ -95,29 +95,32 @@ async def on_POST(self, request, stagetype):

authdict = {"response": response, "session": session}

success = await self.auth_handler.add_oob_auth(
LoginType.RECAPTCHA, authdict, request.getClientIP()
)

if success:
html = self.success_template.render()
else:
try:
await self.auth_handler.add_oob_auth(
LoginType.RECAPTCHA, authdict, request.getClientIP()
)
except LoginError as e:
# Authentication failed, let user try again
html = self.recaptcha_template.render(
session=session,
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.RECAPTCHA),
sitekey=self.hs.config.recaptcha_public_key,
error=e.msg,
clokep marked this conversation as resolved.
Show resolved Hide resolved
)
else:
# No LoginError was raised, so authentication was successful
html = self.success_template.render()

elif stagetype == LoginType.TERMS:
authdict = {"session": session}

success = await self.auth_handler.add_oob_auth(
LoginType.TERMS, authdict, request.getClientIP()
)

if success:
html = self.success_template.render()
else:
try:
await self.auth_handler.add_oob_auth(
LoginType.TERMS, authdict, request.getClientIP()
)
except LoginError as e:
# Authentication failed, let user try again
html = self.terms_template.render(
session=session,
terms_url="%s_matrix/consent?v=%s"
Expand All @@ -127,10 +130,16 @@ async def on_POST(self, request, stagetype):
),
myurl="%s/r0/auth/%s/fallback/web"
% (CLIENT_API_PREFIX, LoginType.TERMS),
error=e.msg,
)
else:
# No LoginError was raised, so authentication was successful
html = self.success_template.render()

elif stagetype == LoginType.SSO:
# The SSO fallback workflow should not post here,
raise SynapseError(404, "Fallback SSO auth does not support POST requests.")

else:
raise SynapseError(404, "Unknown auth stage type")

Expand Down
6 changes: 5 additions & 1 deletion synapse/static/client/register/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ textarea, input {

background-color: #f8f8f8;
border: 1px #ccc solid;
}
}

.error {
color: red;
}