Пример #1
0
def get_test_app(include_admin_routes: Optional[bool] = None, openapi_url: Optional[str] = "/openapi.json") -> FastAPI:
    include_admin_routes = include_admin_routes or get_api_settings().include_admin_routes
    auth_settings = get_auth_settings()
    router_builder = AuthRouterBuilder(auth_settings)
    app = get_auth_app(router_builder, include_admin_routes, openapi_url=openapi_url)
    setup_openapi(app)
    return app
Пример #2
0
 def test_login_password_fails(self) -> None:
     admin_username = get_auth_settings().first_superuser
     assert admin_username is not None
     bad_password = "******"
     message = self._get_login_response(admin_username, bad_password,
                                        APIMessage, HTTP_401_UNAUTHORIZED)
     assert message.detail == "Incorrect password"
Пример #3
0
 def test_read_self(self, non_admin_access_headers: Dict[str, str]) -> None:
     url = self.debug_auth_app.url_path_for(AuthEndpointName.read_self)
     self_user = self.request("GET",
                              url,
                              AuthUser,
                              headers=non_admin_access_headers)
     assert self_user.username == get_auth_settings().first_superuser
Пример #4
0
    def test_remove_expired_tokens(self, monkeypatch: MonkeyPatch) -> None:
        auth_settings = get_auth_settings()

        def real_get_epoch() -> int:
            return timegm(
                datetime.utcnow().utctimetuple())  # seconds since epoch

        assert abs(get_epoch() - real_get_epoch()) <= 1

        def refresh_not_expired_epoch() -> int:
            return real_get_epoch(
            ) + auth_settings.refresh_token_expire_seconds - 100

        def refresh_expired_epoch() -> int:
            return real_get_epoch(
            ) + auth_settings.refresh_token_expire_seconds + 100

        with context_session() as session:
            assert len(session.query(RefreshToken).all()) == 3

            assert remove_expired_tokens(db=session) == 0
            assert len(session.query(RefreshToken).all()) == 3

            monkeypatch.setattr(fastapi_auth.auth_app, "get_epoch",
                                refresh_not_expired_epoch)
            assert remove_expired_tokens(db=session) == 0
            assert len(session.query(RefreshToken).all()) == 3

            monkeypatch.setattr(fastapi_auth.auth_app, "get_epoch",
                                refresh_expired_epoch)
            assert remove_expired_tokens(db=session) == 3

            assert len(session.query(RefreshToken).all()) == 0
Пример #5
0
def test_auth_settings() -> None:
    default_checker = get_auth_settings().password_checker
    new_checker = PasswordChecker([BCryptPasswordHasher()])
    assert default_checker is not new_checker
    get_auth_settings().password_checker = new_checker

    assert get_auth_settings().password_checker is not default_checker
    assert get_auth_settings().password_checker is new_checker

    with pytest.raises(ValidationError) as exc_info:
        get_auth_settings().password_checker = 1  # type: ignore[assignment]
    assert exc_info.value.errors() == [
        {
            "ctx": {"expected_arbitrary_type": "PasswordChecker"},
            "loc": ("password_checker",),
            "msg": "instance of PasswordChecker expected",
            "type": "type_error.arbitrary_type",
        }
    ]
Пример #6
0
 def _get_admin_tokens(self, admin_scope: bool = False) -> AuthTokens:
     auth_settings = get_auth_settings()
     admin_username = auth_settings.first_superuser
     admin_password = auth_settings.first_superuser_password
     assert admin_username is not None
     assert admin_password is not None
     return self._get_login_response(admin_username,
                                     admin_password,
                                     AuthTokens,
                                     admin_scope=admin_scope)
Пример #7
0
def get_reusable_oauth2() -> OAuth2RefreshPasswordBearer:
    settings = get_auth_settings()
    url_base = settings.api_prefix
    token_url = url_base + settings.token_url
    refresh_url = url_base + settings.refresh_url
    scopes = settings.expected_scopes
    return OAuth2RefreshPasswordBearer(token_url=token_url,
                                       refresh_url=refresh_url,
                                       scopes=scopes,
                                       auto_error=True)
Пример #8
0
def test_setup_auth_idempotent(debug_auth_app: FastAPI,
                               caplog: LogCaptureFixture) -> None:
    logger_name = auth_app.__name__
    caplog.set_level(logging.INFO, logger=logger_name)

    auth_settings = get_auth_settings()
    AuthRouterBuilder(auth_settings).setup_first_superuser(get_engine())

    name, level, message = caplog.record_tuples[-1]
    assert name == logger_name
    assert level == logging.INFO
    assert message == "First superuser already exists."
Пример #9
0
def require_superuser() -> Sequence[params.Depends]:
    """
    Returns a list of dependencies containing one that will require superuser access, *UNLESS*
    api_settings indicates otherwise (for development purposes).

    (In that case, no dependencies are added but a warning is emitted.)
    """
    if get_api_settings().disable_superuser_dependency:
        logger.warning(f"*** require_superuser is DISABLED ***")
        return []
    return [
        params.Security(get_jwt_user,
                        scopes=[get_auth_settings().superuser_scope])
    ]
Пример #10
0
def get_test_app_fixture(include_admin_routes: Optional[bool] = None) -> Iterator[FastAPI]:
    test_db_path = Path("./test.db")
    if test_db_path.exists():
        test_db_path.unlink()
    app = get_test_app(include_admin_routes=include_admin_routes)

    engine = get_engine()
    metadata = get_configured_metadata(app)
    metadata.create_all(bind=engine)
    initialize_database(engine)

    auth_settings = get_auth_settings()
    AuthRouterBuilder(auth_settings).setup_first_superuser(engine)

    yield app
    if test_db_path.exists():
        test_db_path.unlink()
Пример #11
0
def generate_tokens(*, user_id: UserID, is_superuser: bool,
                    scopes: List[str]) -> TokenPair:
    auth_settings = get_auth_settings()
    expected_scopes = auth_settings.expected_scopes
    for scope in scopes:
        if scope not in expected_scopes:
            raise_auth_error(detail=f"Unrecognized scope: {scope!r}")

    if auth_settings.superuser_scope in scopes and not is_superuser:
        raise_permissions_error()

    expires_in = auth_settings.access_token_expire_seconds
    access = _generate_token(user_id=user_id,
                             expires_delta=timedelta(seconds=expires_in),
                             scopes=scopes)
    refresh = _generate_token(
        user_id=user_id,
        expires_delta=timedelta(
            seconds=auth_settings.refresh_token_expire_seconds),
        scopes=scopes)
    if auth_settings.include_expires_in_with_tokens:
        return TokenPair(access=access, refresh=refresh, expires_in=expires_in)
    else:
        return TokenPair(access=access, refresh=refresh)
Пример #12
0
def parse_signed_encoding(encoded: str) -> Dict[str, Any]:
    auth_settings = get_auth_settings()
    return jwt.decode(encoded, auth_settings.secret_key, verify=True, algorithms=auth_settings.decoding_algorithms)
Пример #13
0
def generate_signed_encoding(claims: Dict[str, Any], expires_delta: Optional[timedelta]) -> str:
    expiration_claim: Dict[str, int] = {} if expires_delta is None else get_expiration_claim(expires_delta).dict()
    claims.update(expiration_claim)
    auth_settings = get_auth_settings()
    encoded = jwt.encode(claims, auth_settings.secret_key, algorithm=auth_settings.encoding_algorithm)
    return encoded.decode()
Пример #14
0
def prod_auth_app(prod_environment: None) -> Iterator[FastAPI]:
    assert get_auth_settings().include_expires_in_with_tokens is True
    assert get_api_settings().debug is False

    # Try re-adding the middleware
    yield from get_test_app_fixture()
Пример #15
0
def debug_auth_app(debug_environment: None) -> Iterator[FastAPI]:
    assert get_auth_settings().include_expires_in_with_tokens is False
    yield from get_test_app_fixture()
Пример #16
0
def test_default_password() -> None:
    checker = get_auth_settings().password_checker
    password = RawPassword("password")
    hashed = checker.make_sync(password)
    assert checker.check_sync(password, hashed).success
    assert not checker.check_sync(RawPassword("not password"), hashed).success