示例#1
0
 def test_conflict_usernames_same_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)
         self.assertEqual(mock_send_mail.call_count, 1)
         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)
         user2 = users.get_by_email(email)
         self.assertTrue(
             user["activation_key_hash"] != user2["activation_key_hash"])
         self.assertEqual(mock_send_mail.call_count, 2)
示例#2
0
 def test_reissue_activation_key(self, mock_send_mail):
     with app.test_client() as c:
         email = get_random_email()
         response = c.post("/users/me", json={"email": email})
         self.assertEqual(response.status_code, 202)
         user = users.get_by_email(email)
         self.assertTrue(user["activation_key_hash"] is not None)
         response = c.post("/users/me", json={"email": email})
         self.assertEqual(response.status_code, 202)
         user2 = users.get_by_email(email)
         self.assertTrue(
             user["activation_key_hash"] != user2["activation_key_hash"])
         self.assertEqual(mock_send_mail.call_count, 2)
示例#3
0
def request_password_reset():
    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)
    # we are not leaking used or unused e-mails, that's why this responds 202
    if not existing or existing["activated"] is None:
        return "", 202
    local = local_users.get_local_user(existing["uuid"])
    if not local:
        return abort(
            make_response(jsonify(message="User does not have a password"),
                          400))
    pwd_reset_key = guid.uuid4()
    pwd_reset_key_expires = datetime.now().astimezone() + timedelta(hours=1)
    local_users.update_local_user(
        user_uuid=existing["uuid"],
        pwd_reset_key_hash=hashlib.sha256(
            str(pwd_reset_key).encode("utf-8")).hexdigest(),
        pwd_reset_key_expires=pwd_reset_key_expires,
    )
    send_mail.delay(
        [email],
        "PASSWORD_RESET_LINK",
        {
            "pwd_reset_key": pwd_reset_key,
            "pwd_reset_key_expires": int(pwd_reset_key_expires.timestamp()),
            "email": email,
        },
    )
    return "", 202
示例#4
0
 def test_create_user(self, mock_send_mail):
     with app.test_client() as c:
         email = get_random_email()
         c.set_cookie("localhost", "access_token_cookie", TOKEN_ADMIN)
         response = c.post(
             "/organizations/%s/users" % UUID_ORG,
             headers={"x-csrf-token": TOKEN_ADMIN_CSRF},
             json={"role": "user", "email": "    %s    " % email.upper()},
         )
         self.assertEqual(response.status_code, 201)
         self.assertTrue("uuid" in response.json)
         self.assertTrue("username" in response.json)
         self.assertTrue("role" in response.json)
         self.assertTrue("email" in response.json)
         user = users.get_by_email(email)
         self.assertTrue(user is not None)
         self.assertEqual(user["username"], email)
         self.assertEqual(user["email"], email)
         self.assertEqual(user["system_role"], "user")
         luser = local_users.get_local_user(user["uuid"])
         self.assertTrue(luser is None)
         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"] is not None)
         self.assertEqual(args[0][0][2]["email"], email)
         orgrole = organization_roles.get_organization_role(UUID_ORG, user["uuid"])
         self.assertTrue(orgrole["role"], "user")
示例#5
0
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
示例#6
0
 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")
示例#7
0
def reset_password():
    data = request.json
    if not data:
        return abort(make_response(jsonify(message="Missing payload"), 400))
    email = data.get("email", "").lstrip().rstrip().lower()
    pwd_reset_key = data.get("pwd_reset_key", None)
    password = data.get("password", None)
    password_confirmation = data.get("password_confirmation", None)

    try:
        validate_email(email, check_deliverability=False)
    except EmailNotValidError as e:
        return abort(
            make_response(jsonify(message=f"Email not valid: {e}"), 400))
    if not password:
        return abort(make_response(jsonify(message="Missing password"), 400))
    if not pwd_reset_key:
        return abort(make_response(jsonify(message="Missing reset key"), 400))
    if password != password_confirmation:
        return abort(make_response(jsonify(message="Password mismatch"), 400))

    existing = users.get_by_email(email)
    if not existing:
        return abort(make_response(jsonify(message="Cannot reset"), 400))
    local = local_users.get_local_user(existing["uuid"])
    if not local:
        return abort(
            make_response(jsonify(message="User does not have a password"),
                          400))

    if (hashlib.sha256(str(pwd_reset_key).encode("utf-8")).hexdigest() !=
            local["pwd_reset_key_hash"]):
        return abort(make_response(jsonify(message="Cannot reset"), 400))
    if local["pwd_reset_key_expires"] < datetime.now().astimezone():
        return abort(make_response(jsonify(message="Reset key expired"), 400))

    pwd_hash = bcrypt.hashpw(password.encode("utf8"), bcrypt.gensalt())
    local_users.update_local_user(
        user_uuid=existing["uuid"],
        pwd_hash=pwd_hash.decode("utf8"),
        pwd_reset_key_hash=None,
        pwd_reset_key_expires=None,
        force_pwd_change=False,
    )
    send_mail.delay(
        [email],
        "PASSWORD_RESET_CONFIRMATION",
        {
            "email": email,
        },
    )
    return "", 204
示例#8
0
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"]}
示例#9
0
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
示例#10
0
 def test_create_inactive_user(self):
     with app.test_client() as c:
         email = get_random_email()
         # this is testing whitespace truncate and casing as well
         response = c.post("/users/me",
                           json={"email": "   %s    " % email.upper()})
         user = users.get_by_email(email)
         self.assertTrue(user is not None)
         self.assertEqual(user["providers"], [])
         self.assertEqual(user["email"], email)
         self.assertEqual(user["username"], email)
         self.assertEqual(user["activated"], None)
         self.assertTrue(user["activation_key_hash"] is not None)
         self.assertTrue(user["activation_key_expires"] is not None)
         self.assertTrue(
             user["activation_key_expires"] < (datetime.now().astimezone() +
                                               timedelta(minutes=15)))
         self.assertEqual(response.status_code, 202)
示例#11
0
 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)
示例#12
0
def authenticate_base(include_refresh_token):
    data = request.json
    if not data:
        return abort(make_response(jsonify(message="Missing payload"), 400))
    username = data.get("username", None)
    password = data.get("password", None)
    if not username or not password:
        raise BadRequest("Missing username or password in request body.")
    user = users.get_by_email(username.lstrip().rstrip().lower())
    # fallback to legacy username login
    if not user:
        user = users.get_by_username(username)
    if not user:
        raise Unauthorized("Invalid credentials.")

    if user["suspended"]:
        raise Unauthorized("Account suspended")

    local = local_users.get_local_user(user["uuid"])
    if not local:
        raise Unauthorized("Invalid credentials.")
    if not bcrypt.checkpw(password.encode("utf8"),
                          local["pwd_hash"].encode("utf8")):
        raise Unauthorized("Invalid credentials.")
    # drop reset pwd key if any
    if local["pwd_reset_key_hash"]:
        local_users.update_local_user(uuid=user["uuid"],
                                      pwd_reset_key_hash=None,
                                      pwd_reset_key_expires=None)

    userdata = dict(user)
    userdata.update(local)
    response = jsonify(get_user_identity(userdata, True))
    access_token = create_access_token(
        identity=userdata,
        fresh=True,
        expires_delta=ACCESS_TOKEN_EXPIRES_AFTER)
    set_access_cookies(response, access_token)
    if include_refresh_token:
        refresh_token = create_refresh_token(
            identity=userdata, expires_delta=REFRESH_TOKEN_EXPIRES_AFTER)
        set_refresh_cookies(response, refresh_token, 7 * 24 * 60 * 60)
    return response, 200
示例#13
0
 def test_delete(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)
         uuid = response.json["uuid"]
         user = users.get_by_email(email)
         api_tokens.add_token(
             user_uuid=uuid,
             jti=guid.uuid4(),
             organization_uuid=UUID_ORG,
             name="jti",
         )
         self.assertTrue(user["uuid"], uuid)
         response = c.delete(
             "/organizations/%s/users/%s" % (UUID_ORG, uuid),
             headers={"x-csrf-token": TOKEN_ADMIN_CSRF},
         )
         self.assertEqual(response.status_code, 204)
         orgrole = organization_roles.get_organization_role(
             UUID_ORG, user["uuid"])
         tokens = api_tokens.get_tokens_for_user_uuid(user["uuid"],
                                                      org_uuid=UUID_ORG)
         self.assertTrue(user is not None)
         self.assertTrue(orgrole is None)
         for t in tokens:
             self.assertTrue(t["revoked"])
             self.assertTrue(t["organization_uuid"] == UUID_ORG)
         args = mock_send_mail.call_args_list
         self.assertEqual(args[1][0][0][0], email)
         self.assertEqual(args[1][0][1], "ORGANIZATION_REMOVAL")
         self.assertTrue(args[1][0][2]["organization_name"] is not None)
         self.assertTrue(args[1][0][2]["organization_uuid"] is not None)
         self.assertEqual(args[1][0][2]["email"], email)
示例#14
0
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,
    }
示例#15
0
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,
    )