forked from MirrorHub/synapse
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:
commit
f0c06ac65c
4 changed files with 74 additions and 34 deletions
|
@ -25,18 +25,26 @@ import urllib2
|
|||
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(
|
||||
key=shared_secret,
|
||||
msg=user,
|
||||
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 = {
|
||||
"user": user,
|
||||
"password": password,
|
||||
"mac": mac,
|
||||
"type": "org.matrix.login.shared_secret",
|
||||
"admin": admin,
|
||||
}
|
||||
|
||||
server_location = server_location.rstrip("/")
|
||||
|
@ -68,7 +76,7 @@ def request_registration(user, password, server_location, shared_secret):
|
|||
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:
|
||||
try:
|
||||
default_user = getpass.getuser()
|
||||
|
@ -99,7 +107,14 @@ def register_new_user(user, password, server_location, shared_secret):
|
|||
print "Passwords do not match"
|
||||
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__":
|
||||
|
@ -119,6 +134,11 @@ if __name__ == "__main__":
|
|||
default=None,
|
||||
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.add_argument(
|
||||
|
@ -151,4 +171,4 @@ if __name__ == "__main__":
|
|||
else:
|
||||
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)
|
||||
|
|
|
@ -90,7 +90,8 @@ class RegistrationHandler(BaseHandler):
|
|||
password=None,
|
||||
generate_token=True,
|
||||
guest_access_token=None,
|
||||
make_guest=False
|
||||
make_guest=False,
|
||||
admin=False,
|
||||
):
|
||||
"""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
|
||||
None if was_guest else user.localpart
|
||||
),
|
||||
admin=admin,
|
||||
)
|
||||
else:
|
||||
# autogen a sequential user ID
|
||||
|
|
|
@ -324,6 +324,14 @@ class RegisterRestServlet(ClientV1RestServlet):
|
|||
raise SynapseError(400, "Shared secret registration is not enabled")
|
||||
|
||||
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
|
||||
# have the buffer interface
|
||||
|
@ -331,17 +339,21 @@ class RegisterRestServlet(ClientV1RestServlet):
|
|||
|
||||
want_mac = hmac.new(
|
||||
key=self.hs.config.registration_shared_secret,
|
||||
msg=user,
|
||||
digestmod=sha1,
|
||||
).hexdigest()
|
||||
|
||||
password = register_json["password"].encode("utf-8")
|
||||
)
|
||||
want_mac.update(user)
|
||||
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):
|
||||
handler = self.handlers.registration_handler
|
||||
user_id, token = yield handler.register(
|
||||
localpart=user,
|
||||
password=password,
|
||||
admin=bool(admin),
|
||||
)
|
||||
self._remove_session(session)
|
||||
defer.returnValue({
|
||||
|
|
|
@ -77,7 +77,7 @@ class RegistrationStore(SQLBaseStore):
|
|||
@defer.inlineCallbacks
|
||||
def register(self, user_id, token, password_hash,
|
||||
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.
|
||||
|
||||
Args:
|
||||
|
@ -104,6 +104,7 @@ class RegistrationStore(SQLBaseStore):
|
|||
make_guest,
|
||||
appservice_id,
|
||||
create_profile_with_localpart,
|
||||
admin
|
||||
)
|
||||
self.get_user_by_id.invalidate((user_id,))
|
||||
self.is_guest.invalidate((user_id,))
|
||||
|
@ -118,6 +119,7 @@ class RegistrationStore(SQLBaseStore):
|
|||
make_guest,
|
||||
appservice_id,
|
||||
create_profile_with_localpart,
|
||||
admin,
|
||||
):
|
||||
now = int(self.clock.time())
|
||||
|
||||
|
@ -125,29 +127,33 @@ class RegistrationStore(SQLBaseStore):
|
|||
|
||||
try:
|
||||
if was_guest:
|
||||
txn.execute("UPDATE users SET"
|
||||
" password_hash = ?,"
|
||||
" upgrade_ts = ?,"
|
||||
" is_guest = ?"
|
||||
" WHERE name = ?",
|
||||
[password_hash, now, 1 if make_guest else 0, user_id])
|
||||
self._simple_update_one_txn(
|
||||
txn,
|
||||
"users",
|
||||
keyvalues={
|
||||
"name": 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:
|
||||
txn.execute("INSERT INTO users "
|
||||
"("
|
||||
" name,"
|
||||
" password_hash,"
|
||||
" creation_ts,"
|
||||
" is_guest,"
|
||||
" appservice_id"
|
||||
") "
|
||||
"VALUES (?,?,?,?,?)",
|
||||
[
|
||||
user_id,
|
||||
password_hash,
|
||||
now,
|
||||
1 if make_guest else 0,
|
||||
appservice_id,
|
||||
])
|
||||
self._simple_insert_txn(
|
||||
txn,
|
||||
"users",
|
||||
values={
|
||||
"name": user_id,
|
||||
"password_hash": password_hash,
|
||||
"creation_ts": now,
|
||||
"is_guest": 1 if make_guest else 0,
|
||||
"appservice_id": appservice_id,
|
||||
"admin": 1 if admin else 0,
|
||||
}
|
||||
)
|
||||
except self.database_engine.module.IntegrityError:
|
||||
raise StoreError(
|
||||
400, "User ID already taken.", errcode=Codes.USER_IN_USE
|
||||
|
|
Loading…
Reference in a new issue