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

Client / Server Auth Refactor #126

Merged
merged 49 commits into from
Apr 28, 2015
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d98660a
Implement password changing (finally) along with a start on making cl…
dbkr Mar 23, 2015
78adccf
pep8 / pyflakes
dbkr Mar 23, 2015
d19e79e
Make deleting other access tokens when you change your password actua…
dbkr Mar 24, 2015
c7023f2
1) Pushers are now associated with an access token
dbkr Mar 24, 2015
9aa0224
unused import
dbkr Mar 24, 2015
438a21c
Don't test exact equality of the list: as long as it has the fields w…
dbkr Mar 24, 2015
ce2766d
Fix tests
dbkr Mar 24, 2015
c1a256c
Allow multiple pushers for a single app ID & pushkey, honouring the '…
dbkr Mar 25, 2015
df4c12c
pep8 blank lines
dbkr Mar 25, 2015
a32e876
Delete pushers when changing password
dbkr Mar 26, 2015
6f4f7e4
pep8
dbkr Mar 26, 2015
59bf16e
New registration for C/S API v2. Only ReCAPTCHA working currently.
dbkr Mar 30, 2015
46183cc
Add original, unmodified CAPTCHA-SETUP from the webclient repo before…
dbkr Mar 30, 2015
4891c4f
Update CAPTCHA_SETUP (it continues to ignore fallback, but I guess I …
dbkr Mar 30, 2015
9f642a9
pep8
dbkr Mar 31, 2015
d18e777
Grammar and deduplication
dbkr Mar 31, 2015
f129ee1
Make docs a bit more true
dbkr Mar 31, 2015
e9c908e
Completely replace fallback auth for C/S V2:
dbkr Apr 1, 2015
c5bf034
Explain how I justified to myself making JsonResource not always send…
dbkr Apr 1, 2015
70a84f1
Add shared secret auth into register v2 and switch the script over.
dbkr Apr 2, 2015
41cd778
pep8
dbkr Apr 2, 2015
6b59650
Throw sensible errors on not-json when allowing empty body
dbkr Apr 2, 2015
4eb6d66
Add app service auth back in to v2 register
dbkr Apr 2, 2015
a19b739
Regstration with email in v2
dbkr Apr 15, 2015
766bd8e
Dummy login so we can do the first POST request to get login flows wi…
dbkr Apr 15, 2015
ea1776f
Return user ID in use error straight away
dbkr Apr 16, 2015
4cd5fb1
Oops, left debugging in.
dbkr Apr 16, 2015
83b5544
Need to yield the username check, otherwise very very weird things ha…
dbkr Apr 17, 2015
94e1e58
password -> account servlet and add start of an 'add 3pid' endpoint
dbkr Apr 17, 2015
bf5e54f
Register the 3pid servlet
dbkr Apr 17, 2015
cb03faf
Merge branch 'develop' into csauth
dbkr Apr 17, 2015
0b1a850
just the once would probably be fine
dbkr Apr 17, 2015
f96ab9d
make add3pid servlet work
dbkr Apr 17, 2015
4eea5cf
pep8
dbkr Apr 17, 2015
117f35a
Add endpoint to get threepids from server
dbkr Apr 17, 2015
8db6832
Password reset, finally.
dbkr Apr 17, 2015
91c8f82
pep8
dbkr Apr 17, 2015
2e0d921
Remove now-redundant email config
dbkr Apr 23, 2015
a2c10d3
Add an error code to 'missing token' response.
dbkr Apr 23, 2015
0eb61a3
Remove ultimately unused feature of saving params from the first call…
dbkr Apr 23, 2015
03eb4ad
Dedicated error code for failed 3pid auth verification
dbkr Apr 23, 2015
6532b6e
Merge branch 'develop' into csauth
dbkr Apr 24, 2015
f7a79a3
pep8
dbkr Apr 24, 2015
a218619
Use underscores instead of camelcase for id server stuff
dbkr Apr 24, 2015
7ac8a60
More underscores
dbkr Apr 24, 2015
1bac74b
Change to https for ID server communication
dbkr Apr 24, 2015
f1acb9f
logging args
dbkr Apr 27, 2015
03c4f0e
pep8
dbkr Apr 27, 2015
412ece1
Add commentage.
dbkr Apr 27, 2015
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
31 changes: 31 additions & 0 deletions CAPTCHA_SETUP
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Captcha can be enabled for this home server. This file explains how to do that.
The captcha mechanism used is Google's ReCaptcha. This requires API keys from Google.

Getting keys
------------
Requires a public/private key pair from:

https://developers.google.com/recaptcha/


Setting ReCaptcha Keys
----------------------
The keys are a config option on the home server config. If they are not
visible, you can generate them via --generate-config. Set the following value:

recaptcha_public_key: YOUR_PUBLIC_KEY
recaptcha_private_key: YOUR_PRIVATE_KEY

In addition, you MUST enable captchas via:

enable_registration_captcha: true

Configuring IP used for auth
----------------------------
The ReCaptcha API requires that the IP address of the user who solved the
captcha is sent. If the client is connecting through a proxy or load balancer,
it may be required to use the X-Forwarded-For (XFF) header instead of the origin
IP address. This can be configured as an option on the home server like so:

captcha_ip_origin_is_x_forwarded: true

5 changes: 2 additions & 3 deletions register_new_matrix_user
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,17 @@ def request_registration(user, password, server_location, shared_secret):
).hexdigest()

data = {
"user": user,
"username": user,
"password": password,
"mac": mac,
"type": "org.matrix.login.shared_secret",
}

server_location = server_location.rstrip("/")

print "Sending registration request..."

req = urllib2.Request(
"%s/_matrix/client/api/v1/register" % (server_location,),
"%s/_matrix/client/v2_alpha/register" % (server_location,),
data=json.dumps(data),
headers={'Content-Type': 'application/json'}
)
Expand Down
6 changes: 5 additions & 1 deletion static/client/register/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ textarea, input {
margin: auto
}

.g-recaptcha div {
margin: auto;
}

#registrationForm {
text-align: left;
padding: 1em;
padding: 5px;
margin-bottom: 40px;
display: inline-block;

Expand Down
46 changes: 27 additions & 19 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from twisted.internet import defer

from synapse.api.constants import EventTypes, Membership, JoinRules
from synapse.api.errors import AuthError, StoreError, Codes, SynapseError
from synapse.api.errors import AuthError, Codes, SynapseError
from synapse.util.logutils import log_function
from synapse.util.async import run_on_reactor
from synapse.types import UserID, ClientInfo
Expand All @@ -40,6 +40,7 @@ def __init__(self, hs):
self.hs = hs
self.store = hs.get_datastore()
self.state = hs.get_state_handler()
self.TOKEN_NOT_FOUND_HTTP_STATUS = 401

def check(self, event, auth_events):
""" Checks if this event is correctly authed.
Expand Down Expand Up @@ -362,7 +363,10 @@ def get_user_by_req(self, request):

defer.returnValue((user, ClientInfo(device_id, token_id)))
except KeyError:
raise AuthError(403, "Missing access token.")
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Missing access token.",
errcode=Codes.MISSING_TOKEN
)

@defer.inlineCallbacks
def get_user_by_token(self, token):
Expand All @@ -376,33 +380,37 @@ def get_user_by_token(self, token):
Raises:
AuthError if no user by that token exists or the token is invalid.
"""
try:
ret = yield self.store.get_user_by_token(token)
if not ret:
raise StoreError(400, "Unknown token")
user_info = {
"admin": bool(ret.get("admin", False)),
"device_id": ret.get("device_id"),
"user": UserID.from_string(ret.get("name")),
"token_id": ret.get("token_id", None),
}
ret = yield self.store.get_user_by_token(token)
if not ret:
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN
)
user_info = {
"admin": bool(ret.get("admin", False)),
"device_id": ret.get("device_id"),
"user": UserID.from_string(ret.get("name")),
"token_id": ret.get("token_id", None),
}

defer.returnValue(user_info)
except StoreError:
raise AuthError(403, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN)
defer.returnValue(user_info)

@defer.inlineCallbacks
def get_appservice_by_req(self, request):
try:
token = request.args["access_token"][0]
service = yield self.store.get_app_service_by_token(token)
if not service:
raise AuthError(403, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN)
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN
)
defer.returnValue(service)
except KeyError:
raise AuthError(403, "Missing access token.")
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Missing access token."
)

def is_server_admin(self, user):
return self.store.is_server_admin(user)
Expand Down
3 changes: 3 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class LoginType(object):
EMAIL_URL = u"m.login.email.url"
EMAIL_IDENTITY = u"m.login.email.identity"
RECAPTCHA = u"m.login.recaptcha"
DUMMY = u"m.login.dummy"

# Only for C/S API v1
APPLICATION_SERVICE = u"m.login.application_service"
SHARED_SECRET = u"org.matrix.login.shared_secret"

Expand Down
2 changes: 2 additions & 0 deletions synapse/api/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ class Codes(object):
BAD_PAGINATION = "M_BAD_PAGINATION"
UNKNOWN = "M_UNKNOWN"
NOT_FOUND = "M_NOT_FOUND"
MISSING_TOKEN = "M_MISSING_TOKEN"
UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"
LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"
CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
MISSING_PARAM = "M_MISSING_PARAM"
TOO_LARGE = "M_TOO_LARGE"
EXCLUSIVE = "M_EXCLUSIVE"
THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"


class CodeMessageException(RuntimeError):
Expand Down
7 changes: 6 additions & 1 deletion synapse/config/captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class CaptchaConfig(Config):
def __init__(self, args):
super(CaptchaConfig, self).__init__(args)
self.recaptcha_private_key = args.recaptcha_private_key
self.recaptcha_public_key = args.recaptcha_public_key
self.enable_registration_captcha = args.enable_registration_captcha
self.captcha_ip_origin_is_x_forwarded = (
args.captcha_ip_origin_is_x_forwarded
Expand All @@ -30,9 +31,13 @@ def __init__(self, args):
def add_arguments(cls, parser):
super(CaptchaConfig, cls).add_arguments(parser)
group = parser.add_argument_group("recaptcha")
group.add_argument(
"--recaptcha-public-key", type=str, default="YOUR_PUBLIC_KEY",
help="This Home Server's ReCAPTCHA public key."
)
group.add_argument(
"--recaptcha-private-key", type=str, default="YOUR_PRIVATE_KEY",
help="The matching private key for the web client's public key."
help="This Home Server's ReCAPTCHA private key."
)
group.add_argument(
"--enable-registration-captcha", type=bool, default=False,
Expand Down
42 changes: 0 additions & 42 deletions synapse/config/email.py

This file was deleted.

3 changes: 1 addition & 2 deletions synapse/config/homeserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from .ratelimiting import RatelimitConfig
from .repository import ContentRepositoryConfig
from .captcha import CaptchaConfig
from .email import EmailConfig
from .voip import VoipConfig
from .registration import RegistrationConfig
from .metrics import MetricsConfig
Expand All @@ -29,7 +28,7 @@

class HomeServerConfig(TlsConfig, ServerConfig, DatabaseConfig, LoggingConfig,
RatelimitConfig, ContentRepositoryConfig, CaptchaConfig,
EmailConfig, VoipConfig, RegistrationConfig,
VoipConfig, RegistrationConfig,
MetricsConfig, AppServiceConfig,):
pass

Expand Down
4 changes: 4 additions & 0 deletions synapse/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
from .admin import AdminHandler
from .appservice import ApplicationServicesHandler
from .sync import SyncHandler
from .auth import AuthHandler
from .identity import IdentityHandler


class Handlers(object):
Expand Down Expand Up @@ -64,3 +66,5 @@ def __init__(self, hs):
)
)
self.sync_handler = SyncHandler(hs)
self.auth_handler = AuthHandler(hs)
self.identity_handler = IdentityHandler(hs)
Loading