Merge pull request #909 from matrix-org/erikj/shared_secret

Add an admin option to shared secret registration (breaks backwards compat)
This commit is contained in:
Erik Johnston 2016-07-06 14:08:51 +01:00 committed by GitHub
commit f0c06ac65c
4 changed files with 74 additions and 34 deletions

View file

@ -25,18 +25,26 @@ import urllib2
import yaml import yaml
def request_registration(user, password, server_location, shared_secret): def request_registration(user, password, server_location, shared_secret, admin=False):
mac = hmac.new( mac = hmac.new(
key=shared_secret, key=shared_secret,
msg=user,
digestmod=hashlib.sha1, digestmod=hashlib.sha1,
).hexdigest() )
mac.update(user)
mac.update("\x00")
mac.update(password)
mac.update("\x00")
mac.update("admin" if admin else "notadmin")
mac = mac.hexdigest()
data = { data = {
"user": user, "user": user,
"password": password, "password": password,
"mac": mac, "mac": mac,
"type": "org.matrix.login.shared_secret", "type": "org.matrix.login.shared_secret",
"admin": admin,
} }
server_location = server_location.rstrip("/") server_location = server_location.rstrip("/")
@ -68,7 +76,7 @@ def request_registration(user, password, server_location, shared_secret):
sys.exit(1) sys.exit(1)
def register_new_user(user, password, server_location, shared_secret): def register_new_user(user, password, server_location, shared_secret, admin):
if not user: if not user:
try: try:
default_user = getpass.getuser() default_user = getpass.getuser()
@ -99,7 +107,14 @@ def register_new_user(user, password, server_location, shared_secret):
print "Passwords do not match" print "Passwords do not match"
sys.exit(1) sys.exit(1)
request_registration(user, password, server_location, shared_secret) if not admin:
admin = raw_input("Make admin [no]: ")
if admin in ("y", "yes", "true"):
admin = True
else:
admin = False
request_registration(user, password, server_location, shared_secret, bool(admin))
if __name__ == "__main__": if __name__ == "__main__":
@ -119,6 +134,11 @@ if __name__ == "__main__":
default=None, default=None,
help="New password for user. Will prompt if omitted.", help="New password for user. Will prompt if omitted.",
) )
parser.add_argument(
"-a", "--admin",
action="store_true",
help="Register new user as an admin. Will prompt if omitted.",
)
group = parser.add_mutually_exclusive_group(required=True) group = parser.add_mutually_exclusive_group(required=True)
group.add_argument( group.add_argument(
@ -151,4 +171,4 @@ if __name__ == "__main__":
else: else:
secret = args.shared_secret secret = args.shared_secret
register_new_user(args.user, args.password, args.server_url, secret) register_new_user(args.user, args.password, args.server_url, secret, args.admin)

View file

@ -90,7 +90,8 @@ class RegistrationHandler(BaseHandler):
password=None, password=None,
generate_token=True, generate_token=True,
guest_access_token=None, guest_access_token=None,
make_guest=False make_guest=False,
admin=False,
): ):
"""Registers a new client on the server. """Registers a new client on the server.
@ -141,6 +142,7 @@ class RegistrationHandler(BaseHandler):
# If the user was a guest then they already have a profile # If the user was a guest then they already have a profile
None if was_guest else user.localpart None if was_guest else user.localpart
), ),
admin=admin,
) )
else: else:
# autogen a sequential user ID # autogen a sequential user ID

View file

@ -324,6 +324,14 @@ class RegisterRestServlet(ClientV1RestServlet):
raise SynapseError(400, "Shared secret registration is not enabled") raise SynapseError(400, "Shared secret registration is not enabled")
user = register_json["user"].encode("utf-8") user = register_json["user"].encode("utf-8")
password = register_json["password"].encode("utf-8")
admin = register_json.get("admin", None)
# Its important to check as we use null bytes as HMAC field separators
if "\x00" in user:
raise SynapseError(400, "Invalid user")
if "\x00" in password:
raise SynapseError(400, "Invalid password")
# str() because otherwise hmac complains that 'unicode' does not # str() because otherwise hmac complains that 'unicode' does not
# have the buffer interface # have the buffer interface
@ -331,17 +339,21 @@ class RegisterRestServlet(ClientV1RestServlet):
want_mac = hmac.new( want_mac = hmac.new(
key=self.hs.config.registration_shared_secret, key=self.hs.config.registration_shared_secret,
msg=user,
digestmod=sha1, digestmod=sha1,
).hexdigest() )
want_mac.update(user)
password = register_json["password"].encode("utf-8") want_mac.update("\x00")
want_mac.update(password)
want_mac.update("\x00")
want_mac.update("admin" if admin else "notadmin")
want_mac = want_mac.hexdigest()
if compare_digest(want_mac, got_mac): if compare_digest(want_mac, got_mac):
handler = self.handlers.registration_handler handler = self.handlers.registration_handler
user_id, token = yield handler.register( user_id, token = yield handler.register(
localpart=user, localpart=user,
password=password, password=password,
admin=bool(admin),
) )
self._remove_session(session) self._remove_session(session)
defer.returnValue({ defer.returnValue({

View file

@ -77,7 +77,7 @@ class RegistrationStore(SQLBaseStore):
@defer.inlineCallbacks @defer.inlineCallbacks
def register(self, user_id, token, password_hash, def register(self, user_id, token, password_hash,
was_guest=False, make_guest=False, appservice_id=None, was_guest=False, make_guest=False, appservice_id=None,
create_profile_with_localpart=None): create_profile_with_localpart=None, admin=False):
"""Attempts to register an account. """Attempts to register an account.
Args: Args:
@ -104,6 +104,7 @@ class RegistrationStore(SQLBaseStore):
make_guest, make_guest,
appservice_id, appservice_id,
create_profile_with_localpart, create_profile_with_localpart,
admin
) )
self.get_user_by_id.invalidate((user_id,)) self.get_user_by_id.invalidate((user_id,))
self.is_guest.invalidate((user_id,)) self.is_guest.invalidate((user_id,))
@ -118,6 +119,7 @@ class RegistrationStore(SQLBaseStore):
make_guest, make_guest,
appservice_id, appservice_id,
create_profile_with_localpart, create_profile_with_localpart,
admin,
): ):
now = int(self.clock.time()) now = int(self.clock.time())
@ -125,29 +127,33 @@ class RegistrationStore(SQLBaseStore):
try: try:
if was_guest: if was_guest:
txn.execute("UPDATE users SET" self._simple_update_one_txn(
" password_hash = ?," txn,
" upgrade_ts = ?," "users",
" is_guest = ?" keyvalues={
" WHERE name = ?", "name": user_id,
[password_hash, now, 1 if make_guest else 0, user_id]) },
updatevalues={
"password_hash": password_hash,
"upgrade_ts": now,
"is_guest": 1 if make_guest else 0,
"appservice_id": appservice_id,
"admin": 1 if admin else 0,
}
)
else: else:
txn.execute("INSERT INTO users " self._simple_insert_txn(
"(" txn,
" name," "users",
" password_hash," values={
" creation_ts," "name": user_id,
" is_guest," "password_hash": password_hash,
" appservice_id" "creation_ts": now,
") " "is_guest": 1 if make_guest else 0,
"VALUES (?,?,?,?,?)", "appservice_id": appservice_id,
[ "admin": 1 if admin else 0,
user_id, }
password_hash, )
now,
1 if make_guest else 0,
appservice_id,
])
except self.database_engine.module.IntegrityError: except self.database_engine.module.IntegrityError:
raise StoreError( raise StoreError(
400, "User ID already taken.", errcode=Codes.USER_IN_USE 400, "User ID already taken.", errcode=Codes.USER_IN_USE