mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-05-02 08:46:04 -04:00
Merge remote-tracking branch 'origin/develop' into rav/saml_mapping_work
This commit is contained in:
commit
ed8b92f0d2
51 changed files with 844 additions and 235 deletions
|
@ -103,16 +103,9 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
# Have the configured identity server handle the request
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Password reset by email is not supported on this homeserver"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
@ -200,7 +193,7 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
"""Handles 3PID validation token submission"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/password_reset/(?P<medium>[^/]*)/submit_token/*$", releases=(), unstable=True
|
||||
"/password_reset/(?P<medium>[^/]*)/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
|
@ -214,6 +207,11 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
|
@ -261,34 +259,12 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, medium):
|
||||
if medium != "email":
|
||||
raise SynapseError(
|
||||
400, "This medium is currently not supported for password resets"
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["sid", "client_secret", "token"])
|
||||
|
||||
valid, _ = yield self.store.validate_threepid_session(
|
||||
body["sid"], body["client_secret"], body["token"], self.clock.time_msec()
|
||||
)
|
||||
response_code = 200 if valid else 400
|
||||
|
||||
return response_code, {"success": valid}
|
||||
|
||||
|
||||
class PasswordRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/password$")
|
||||
|
@ -416,13 +392,35 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.store = self.hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
template_html, template_text = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[
|
||||
self.config.email_add_threepid_template_html,
|
||||
self.config.email_add_threepid_template_text,
|
||||
],
|
||||
public_baseurl=self.config.public_baseurl,
|
||||
)
|
||||
self.mailer = Mailer(
|
||||
hs=self.hs,
|
||||
app_name=self.config.email_app_name,
|
||||
template_html=template_html,
|
||||
template_text=template_text,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(
|
||||
body, ["id_server", "client_secret", "email", "send_attempt"]
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
||||
client_secret = body["client_secret"]
|
||||
email = body["email"]
|
||||
send_attempt = body["send_attempt"]
|
||||
|
@ -442,9 +440,30 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
id_server, email, client_secret, send_attempt, next_link
|
||||
)
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
else:
|
||||
# Send threepid validation emails from Synapse
|
||||
sid = yield self.identity_handler.send_threepid_validation(
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
self.mailer.send_add_threepid_mail,
|
||||
next_link,
|
||||
)
|
||||
|
||||
# Wrap the session id in a JSON object
|
||||
ret = {"sid": sid}
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
|
@ -461,10 +480,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
def on_POST(self, request):
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(
|
||||
body,
|
||||
["id_server", "client_secret", "country", "phone_number", "send_attempt"],
|
||||
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
client_secret = body["client_secret"]
|
||||
country = body["country"]
|
||||
phone_number = body["phone_number"]
|
||||
|
@ -485,12 +502,146 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
if not self.hs.config.account_threepid_delegate_msisdn:
|
||||
logger.warn(
|
||||
"No upstream msisdn account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400,
|
||||
"Adding phone numbers to user account is not supported by this homeserver",
|
||||
)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(
|
||||
id_server, country, phone_number, client_secret, send_attempt, next_link
|
||||
self.hs.config.account_threepid_delegate_msisdn,
|
||||
country,
|
||||
phone_number,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
class AddThreepidEmailSubmitTokenServlet(RestServlet):
|
||||
"""Handles 3PID validation token submission for adding an email to a user's account"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/add_threepid/email/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super().__init__()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_add_threepid_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
elif self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"This homeserver is not validating threepids. Use an identity server "
|
||||
"instead.",
|
||||
)
|
||||
|
||||
sid = parse_string(request, "sid", required=True)
|
||||
client_secret = parse_string(request, "client_secret", required=True)
|
||||
token = parse_string(request, "token", required=True)
|
||||
|
||||
# Attempt to validate a 3PID session
|
||||
try:
|
||||
# Mark the session as valid
|
||||
next_link = yield self.store.validate_threepid_session(
|
||||
sid, client_secret, token, self.clock.time_msec()
|
||||
)
|
||||
|
||||
# Perform a 302 redirect if next_link is set
|
||||
if next_link:
|
||||
if next_link.startswith("file:///"):
|
||||
logger.warn(
|
||||
"Not redirecting to next_link as it is a local file: address"
|
||||
)
|
||||
else:
|
||||
request.setResponseCode(302)
|
||||
request.setHeader("Location", next_link)
|
||||
finish_request(request)
|
||||
return None
|
||||
|
||||
# Otherwise show the success template
|
||||
html = self.config.email_add_threepid_template_success_html_content
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
|
||||
class AddThreepidMsisdnSubmitTokenServlet(RestServlet):
|
||||
"""Handles 3PID validation token submission for adding a phone number to a user's
|
||||
account
|
||||
"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/add_threepid/msisdn/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super().__init__()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
if not self.config.account_threepid_delegate_msisdn:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"This homeserver is not validating phone numbers. Use an identity server "
|
||||
"instead.",
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["client_secret", "sid", "token"])
|
||||
|
||||
# Proxy submit_token request to msisdn threepid delegate
|
||||
response = yield self.identity_handler.proxy_msisdn_submit_token(
|
||||
self.config.account_threepid_delegate_msisdn,
|
||||
body["client_secret"],
|
||||
body["sid"],
|
||||
body["token"],
|
||||
)
|
||||
return 200, response
|
||||
|
||||
|
||||
class ThreepidRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid$")
|
||||
|
||||
|
@ -512,6 +663,8 @@ class ThreepidRestServlet(RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds")
|
||||
|
@ -519,34 +672,96 @@ class ThreepidRestServlet(RestServlet):
|
|||
raise SynapseError(
|
||||
400, "Missing param three_pid_creds", Codes.MISSING_PARAM
|
||||
)
|
||||
assert_params_in_dict(threepid_creds, ["client_secret", "sid"])
|
||||
|
||||
client_secret = threepid_creds["client_secret"]
|
||||
sid = threepid_creds["sid"]
|
||||
|
||||
validation_session = yield self.identity_handler.validate_threepid_session(
|
||||
client_secret, sid
|
||||
)
|
||||
if validation_session:
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id,
|
||||
validation_session["medium"],
|
||||
validation_session["address"],
|
||||
validation_session["validated_at"],
|
||||
)
|
||||
return 200, {}
|
||||
|
||||
raise SynapseError(
|
||||
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
|
||||
)
|
||||
|
||||
|
||||
class ThreepidAddRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/add$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidAddRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.auth = hs.get_auth()
|
||||
self.auth_handler = hs.get_auth_handler()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(body, ["client_secret", "sid"])
|
||||
client_secret = body["client_secret"]
|
||||
sid = body["sid"]
|
||||
|
||||
validation_session = yield self.identity_handler.validate_threepid_session(
|
||||
client_secret, sid
|
||||
)
|
||||
if validation_session:
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id,
|
||||
validation_session["medium"],
|
||||
validation_session["address"],
|
||||
validation_session["validated_at"],
|
||||
)
|
||||
return 200, {}
|
||||
|
||||
raise SynapseError(
|
||||
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
|
||||
)
|
||||
|
||||
|
||||
class ThreepidBindRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/bind$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidBindRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(body, ["id_server", "sid", "client_secret"])
|
||||
id_server = body["id_server"]
|
||||
sid = body["sid"]
|
||||
client_secret = body["client_secret"]
|
||||
id_access_token = body.get("id_access_token") # optional
|
||||
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
|
||||
# Specify None as the identity server to retrieve it from the request body instead
|
||||
threepid = yield self.identity_handler.threepid_from_creds(None, threepid_creds)
|
||||
|
||||
if not threepid:
|
||||
raise SynapseError(400, "Failed to auth 3pid", Codes.THREEPID_AUTH_FAILED)
|
||||
|
||||
for reqd in ["medium", "address", "validated_at"]:
|
||||
if reqd not in threepid:
|
||||
logger.warn("Couldn't add 3pid: invalid response from ID server")
|
||||
raise SynapseError(500, "Invalid response from ID Server")
|
||||
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id, threepid["medium"], threepid["address"], threepid["validated_at"]
|
||||
yield self.identity_handler.bind_threepid(
|
||||
client_secret, sid, user_id, id_server, id_access_token
|
||||
)
|
||||
|
||||
if "bind" in body and body["bind"]:
|
||||
logger.debug("Binding threepid %s to %s", threepid, user_id)
|
||||
yield self.identity_handler.bind_threepid(threepid_creds, user_id)
|
||||
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ThreepidUnbindRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/unbind$")
|
||||
PATTERNS = client_patterns("/account/3pid/unbind$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidUnbindRestServlet, self).__init__()
|
||||
|
@ -634,7 +849,11 @@ def register_servlets(hs, http_server):
|
|||
DeactivateAccountRestServlet(hs).register(http_server)
|
||||
EmailThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
AddThreepidEmailSubmitTokenServlet(hs).register(http_server)
|
||||
AddThreepidMsisdnSubmitTokenServlet(hs).register(http_server)
|
||||
ThreepidRestServlet(hs).register(http_server)
|
||||
ThreepidAddRestServlet(hs).register(http_server)
|
||||
ThreepidBindRestServlet(hs).register(http_server)
|
||||
ThreepidUnbindRestServlet(hs).register(http_server)
|
||||
ThreepidDeleteRestServlet(hs).register(http_server)
|
||||
WhoamiRestServlet(hs).register(http_server)
|
||||
|
|
|
@ -131,15 +131,9 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Registration by email is not supported on this homeserver"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
@ -246,6 +240,18 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
if medium != "email":
|
||||
|
@ -289,17 +295,11 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
# Show a failure page with a reason
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
@ -334,6 +334,11 @@ class UsernameAvailabilityRestServlet(RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
if not self.hs.config.enable_registration:
|
||||
raise SynapseError(
|
||||
403, "Registration has been disabled", errcode=Codes.FORBIDDEN
|
||||
)
|
||||
|
||||
ip = self.hs.get_ip_from_request(request)
|
||||
with self.ratelimiter.ratelimit(ip) as wait_deferred:
|
||||
yield wait_deferred
|
||||
|
|
|
@ -48,7 +48,24 @@ class VersionsRestServlet(RestServlet):
|
|||
"r0.5.0",
|
||||
],
|
||||
# as per MSC1497:
|
||||
"unstable_features": {"m.lazy_load_members": True},
|
||||
"unstable_features": {
|
||||
"m.lazy_load_members": True,
|
||||
# as per MSC2190, as amended by MSC2264
|
||||
# to be removed in r0.6.0
|
||||
"m.id_access_token": True,
|
||||
# Advertise to clients that they need not include an `id_server`
|
||||
# parameter during registration or password reset, as Synapse now decides
|
||||
# itself which identity server to use (or none at all).
|
||||
#
|
||||
# This is also used by a client when they wish to bind a 3PID to their
|
||||
# account, but not bind it to an identity server, the endpoint for which
|
||||
# also requires `id_server`. If the homeserver is handling 3PID
|
||||
# verification itself, there is no need to ask the user for `id_server` to
|
||||
# be supplied.
|
||||
"m.require_identity_server": False,
|
||||
# as per MSC2290
|
||||
"m.separate_add_and_bind": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue