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

Commit

Permalink
Merge pull request #126 from matrix-org/csauth
Browse files Browse the repository at this point in the history
Client / Server Auth Refactor
  • Loading branch information
NegativeMjark committed Apr 28, 2015
2 parents 55fcf62 + 412ece1 commit 9182f87
Show file tree
Hide file tree
Showing 34 changed files with 1,323 additions and 287 deletions.
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 @@ -369,7 +370,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 @@ -383,33 +387,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

0 comments on commit 9182f87

Please sign in to comment.