def update_user(uuid): admin_uuid = get_jwt_identity() if admin_uuid == uuid: return abort(make_response("", 409)) user = users.get_by_uuid(uuid) if user is None: return abort(make_response("", 404)) data = request.json if not data: return abort(make_response("", 400)) role = data.get("role", user["role"]) suspended = data.get("suspended", user["suspended"]) if role not in ["admin", "user"]: return abort(make_response("", 400)) user["role"] = role user["suspended"] = suspended users.update_user(**user) return ( jsonify({ "uuid": user["uuid"], "username": user["username"], "role": role, "suspended": suspended, }), 200, )
def activate_user(): data = request.json if not data: return abort(make_response(jsonify(message="Missing payload"), 400)) email = data.get("email", "").lstrip().rstrip().lower() activation_key = data.get("activation_key", None) password = data.get("password", None) password_confirmation = data.get("password_confirmation", None) if not email or not is_email(email): return abort( make_response(jsonify(message="Missing or bad email"), 400)) if not password: return abort(make_response(jsonify(message="Missing password"), 400)) if not activation_key: return abort( make_response(jsonify(message="Missing activation_key"), 400)) if password != password_confirmation: return abort( make_response(jsonify(message="Passwords do not match"), 400)) existing = users.get_by_email(email) if not existing: return abort(make_response(jsonify(message="Cannot activate"), 400)) if existing["activated"] is not None: return abort(make_response(jsonify(message="Already activated"), 409)) if (hashlib.sha256(str(activation_key).encode("utf-8")).hexdigest() != existing["activation_key_hash"]): return abort(make_response(jsonify(message="Cannot activate"), 400)) if existing["activation_key_expires"] < datetime.now().astimezone(): return abort( make_response(jsonify(message="Activation key expired"), 400)) memberships = organization_roles.get_by_user_uuid(existing["uuid"]) if len(memberships) == 0: orguuid = guid.uuid4() organizations.add_organization(uuid=orguuid, name="Default organization") organization_roles.set_organization_role(orguuid, existing["uuid"], "admin") pwd_hash = bcrypt.hashpw(password.encode("utf8"), bcrypt.gensalt()) users.update_user( uuid=existing["uuid"], activated=datetime.now().astimezone(), providers=["local"], providers_data={}, ) local_users.add_local_user( user_uuid=existing["uuid"], pwd_hash=pwd_hash.decode("utf8"), force_pwd_change=False, ) return "", 204
def test_existing_user_different_org(self, mock_send_mail): with app.test_client() as c: c.set_cookie("localhost", "access_token_cookie", TOKEN_ADMIN) username = get_random_username() email = get_random_email() response = c.post( "/organizations/%s/users" % UUID_ORG, headers={"x-csrf-token": TOKEN_ADMIN_CSRF}, json={ "username": username, "role": "user", "email": email }, ) self.assertEqual(response.status_code, 201) user = users.get_by_email(email) args = mock_send_mail.call_args_list self.assertEqual(args[0][0][0][0], email) self.assertEqual(args[0][0][1], "REGISTRATION_VERIFICATION_EMAIL") self.assertTrue(args[0][0][2]["activation_key"] is not None) self.assertTrue( args[0][0][2]["activation_key_expires"] is not None) self.assertTrue(args[0][0][2]["organization_name"] is not None) self.assertTrue(args[0][0][2]["organization_uuid"] == UUID_ORG) self.assertEqual(args[0][0][2]["email"], email) orgrole = organization_roles.get_organization_role( UUID_ORG, user["uuid"]) self.assertTrue(orgrole["role"], "user") # fake activate users.update_user(uuid=user["uuid"], activated=datetime.now()) c.set_cookie("localhost", "access_token_cookie", TOKEN_USER) response = c.post( "/organizations/%s/users" % UUID_ORG2, headers={"x-csrf-token": TOKEN_USER_CSRF}, json={ "username": username, "role": "user", "email": email }, ) self.assertEqual(response.status_code, 201) args = mock_send_mail.call_args_list self.assertEqual(args[1][0][0][0], email) self.assertEqual(args[1][0][1], "ORGANIZATION_INVITATION") self.assertTrue("activation_key" not in args[1][0][2]) self.assertTrue("activation_key_expires" not in args[1][0][2]) self.assertTrue(args[1][0][2]["organization_name"] is not None) self.assertTrue(args[1][0][2]["organization_uuid"] == UUID_ORG2) self.assertEqual(args[1][0][2]["email"], email) orgrole = organization_roles.get_organization_role( UUID_ORG2, user["uuid"]) self.assertTrue(orgrole["role"], "user")
def activate_user(email, activation_key, password, password_confirmation): try: validate_email(email, check_deliverability=False) except EmailNotValidError as e: return {"activated": False, "message": f"Email not valid: {e}"} if not password: return {"activated": False, "message": "Missing password"} if not activation_key: return {"activated": False, "message": "Missing activation_key"} if password != password_confirmation: return {"activated": False, "message": "Passwords do not match"} existing = users.get_by_email(email) if not existing: return {"activated": False, "message": "Cannot activate"} if existing["activated"] is not None: return { "activated": False, "already_activated": True, "message": "Already activated", } if (hashlib.sha256(str(activation_key).encode("utf-8")).hexdigest() != existing["activation_key_hash"]): return {"activated": False, "message": "Cannot activate"} if existing["activation_key_expires"] < datetime.now().astimezone(): return {"activated": False, "message": "Activation key expired"} memberships = organization_roles.get_by_user_uuid(existing["uuid"]) if len(memberships) == 0: orguuid = guid.uuid4() organizations.add_organization(uuid=orguuid, name="Default organization") organization_roles.set_organization_role(orguuid, existing["uuid"], "admin") pwd_hash = bcrypt.hashpw(password.encode("utf8"), bcrypt.gensalt()) users.update_user( uuid=existing["uuid"], activated=datetime.now().astimezone(), providers=["local"], providers_data={}, ) local_users.add_local_user( user_uuid=existing["uuid"], pwd_hash=pwd_hash.decode("utf8"), force_pwd_change=False, ) return {"activated": True, "user_uuid": existing["uuid"]}
def create_inactive_user(): data = request.json if not data: return abort(make_response(jsonify(message="Missing payload"), 400)) email = data.get("email", "").lstrip().rstrip().lower() if not email or not is_email(email): return abort( make_response(jsonify(message="Missing or bad email"), 400)) existing = users.get_by_email(email) # activated users if existing and existing["activated"] is not None: return "", 202 activation_key = guid.uuid4() activation_key_expires = datetime.now().astimezone() + timedelta( minutes=10) # reissue activation_key if existing: users.update_user( uuid=existing["uuid"], activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8")).hexdigest(), activation_key_expires=activation_key_expires, ) # completely new user else: users.add_user( uuid=guid.uuid4(), username=email, email=email, system_role="user", providers=[], activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8")).hexdigest(), activation_key_expires=activation_key_expires, ) send_mail.delay( [email], "REGISTRATION_VERIFICATION_EMAIL", { "activation_key": activation_key, "activation_key_expires": int(activation_key_expires.timestamp()), "email": email, }, ) return "", 202
def test_send_email_with_reset_link(self, mock_send_mail): with app.test_client() as c: email = get_random_email() c.post("/users/me", json={"email": email}) user = users.get_by_email(email) users.update_user(uuid=user["uuid"], activated=datetime.now()) local_users.add_local_user(user_uuid=user["uuid"], pwd_hash="aaa", force_pwd_change=False) response = c.post("/users/me/request-password-reset", json={"email": email}) self.assertEqual(response.status_code, 202) self.assertEqual(mock_send_mail.call_count, 2) args = mock_send_mail.call_args_list self.assertEqual(args[1][0][0][0], email) self.assertEqual(args[1][0][1], "PASSWORD_RESET_LINK") self.assertTrue(args[1][0][2]["pwd_reset_key"] is not None) self.assertTrue(args[1][0][2]["pwd_reset_key_expires"] is not None) self.assertEqual(args[1][0][2]["email"], email)
def patch_user(): data = request.json username = data.get("username", None) if not username: return abort(make_response(jsonify(message="Missing username"), 400)) user = get_current_user() if not user: return abort(make_response(jsonify(message="Unauthorized"), 401)) existing = users.get_by_username(username) if existing and existing["uuid"] != user["uuid"]: return abort(make_response(jsonify(message="Cannot patch"), 400)) users.update_user(uuid=user["uuid"], username=username) userdata = dict(user) userdata["username"] = username response = jsonify(get_user_identity(userdata, True)) return response, 200
def test_add_existing_user_fails(self, mock_send_mail): with app.test_client() as c: c.set_cookie("localhost", "access_token_cookie", TOKEN_ADMIN) email = get_random_email() response = c.post( "/organizations/%s/users" % UUID_ORG, headers={"x-csrf-token": TOKEN_ADMIN_CSRF}, json={"role": "user", "email": email,}, ) self.assertEqual(response.status_code, 201) user = json.loads(response.data) users.update_user(uuid=user["uuid"], activated=datetime.now()) response = c.post( "/organizations/%s/users" % UUID_ORG, headers={"x-csrf-token": TOKEN_ADMIN_CSRF}, json={"role": "user", "email": email,}, ) self.assertEqual(response.status_code, 409)
def create_inactive_user(email): existing = users.get_by_email(email) # activated users if existing and existing["activated"] is not None: return {"created": False, "user_uuid": existing["uuid"]} activation_key = guid.uuid4() activation_key_expires = datetime.now().astimezone() + timedelta( minutes=10) user_uuid = guid.uuid4() # reissue activation_key if existing: users.update_user( uuid=existing["uuid"], activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8")).hexdigest(), activation_key_expires=activation_key_expires, ) user_uuid = existing["uuid"] # completely new user else: users.add_user( uuid=user_uuid, username=email, email=email, system_role="user", providers=[], activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8")).hexdigest(), activation_key_expires=activation_key_expires, ) return { "created": True, "activation_key": str(activation_key), "activation_key_expires": activation_key_expires, "email": email, "user_uuid": user_uuid, }
def add_user_to_org(org_uuid): data = request.json if not data: return abort(make_response(jsonify(message="Missing payload"), 400)) email = data.get("email", None) org_role = data.get("role", None) if not email or not org_role: return abort(make_response(jsonify(message="Missing email"), 400)) if org_role not in ["admin", "user"]: return abort(make_response(jsonify(message="Bad role"), 400)) email = email.lstrip().rstrip().lower() if not is_email(email): return abort(make_response(jsonify(message="Invalid email"), 400)) existing = users.get_by_email(email) # completely new user if existing is None: user_uuid = guid.uuid4() activation_key = guid.uuid4() activation_key_expires = datetime.now().astimezone() + timedelta(hours=24) users.add_user( uuid=user_uuid, email=email, username=email, system_role="user", providers=[], activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8") ).hexdigest(), activation_key_expires=activation_key_expires, ) else: user_uuid = existing.get("uuid", None) # an activated account that already has a role in this organization if ( organization_roles.get_organization_role(org_uuid, user_uuid) and existing["activated"] ): return abort(make_response(jsonify(message="User already exists"), 409)) # an account that is not activated but has already been sent an invite activation_key = guid.uuid4() activation_key_expires = datetime.now().astimezone() + timedelta(hours=24) users.update_user( uuid=user_uuid, activation_key_hash=hashlib.sha256( str(activation_key).encode("utf-8") ).hexdigest(), activation_key_expires=activation_key_expires, ) organization = organizations.get_by_uuid(org_uuid) organization_roles.set_organization_role(org_uuid, user_uuid, org_role) if existing is None or existing["activated"] is None: send_mail.delay( [email], "REGISTRATION_VERIFICATION_EMAIL", { "activation_key": activation_key, "activation_key_expires": int(activation_key_expires.timestamp()), "email": email, "inviter_username": get_current_user()["username"], "organization_name": organization["name"], "organization_uuid": organization["uuid"], }, ) else: send_mail.delay( [email], "ORGANIZATION_INVITATION", { "email": email, "inviter_username": get_current_user()["username"], "organization_name": organization["name"], "organization_uuid": organization["uuid"], }, ) return ( jsonify( { "uuid": str(user_uuid), "username": existing["username"] if existing else email, "email": email, "role": org_role, "activated": existing["activated"] is not None if existing else False, } ), 201, )