openauth-plugins 0.0.4

Official OpenAuth plugin modules.
Documentation
use std::sync::Arc;

use openauth_core::api::AuthRouter;
use openauth_core::context::create_auth_context_with_adapter;
use openauth_core::db::MemoryAdapter;
use openauth_core::options::OpenAuthOptions;
use openauth_plugins::admin::{admin, AdminOptions, AdminSchemaOptions};

#[test]
fn custom_schema_overrides_change_physical_field_names() -> Result<(), Box<dyn std::error::Error>> {
    let context = create_auth_context_with_adapter(
        OpenAuthOptions {
            plugins: vec![admin(AdminOptions {
                schema: AdminSchemaOptions {
                    user_role_field: "admin_role".to_owned(),
                    user_banned_field: "is_banned".to_owned(),
                    user_ban_reason_field: "ban_note".to_owned(),
                    user_ban_expires_field: "ban_until".to_owned(),
                    session_impersonated_by_field: "impersonator_id".to_owned(),
                },
                ..AdminOptions::default()
            })],
            secret: Some(secret()),
            ..OpenAuthOptions::default()
        },
        Arc::new(MemoryAdapter::new()),
    )?;

    assert_eq!(context.db_schema.field("user", "role")?.name, "admin_role");
    assert_eq!(context.db_schema.field("user", "banned")?.name, "is_banned");
    assert_eq!(
        context.db_schema.field("user", "ban_reason")?.name,
        "ban_note"
    );
    assert_eq!(
        context.db_schema.field("user", "ban_expires")?.name,
        "ban_until"
    );
    assert_eq!(
        context.db_schema.field("session", "impersonated_by")?.name,
        "impersonator_id"
    );
    Ok(())
}

#[test]
fn admin_endpoints_expose_detailed_openapi() -> Result<(), Box<dyn std::error::Error>> {
    let context = create_auth_context_with_adapter(
        OpenAuthOptions {
            base_url: Some("http://localhost:3000".to_owned()),
            plugins: vec![admin(AdminOptions::default())],
            secret: Some(secret()),
            ..OpenAuthOptions::default()
        },
        Arc::new(MemoryAdapter::new()),
    )?;
    let router = AuthRouter::with_async_endpoints(context, Vec::new(), Vec::new())?;
    let openapi = router.openapi_schema();

    let create_user = &openapi["paths"]["/admin/create-user"]["post"];
    assert_eq!(create_user["operationId"], "createUser");
    assert!(create_user["tags"]
        .as_array()
        .ok_or("missing tags")?
        .iter()
        .any(|tag| tag == "Admin"));
    assert_eq!(
        create_user["requestBody"]["content"]["application/json"]["schema"]["properties"]
            ["password"]["minLength"],
        8
    );
    assert_eq!(
        create_user["responses"]["200"]["content"]["application/json"]["schema"]["properties"]
            ["user"]["$ref"],
        "#/components/schemas/User"
    );

    let list_users = &openapi["paths"]["/admin/list-users"]["get"];
    assert_eq!(list_users["operationId"], "listUsers");
    let parameters = list_users["parameters"]
        .as_array()
        .ok_or("missing parameters")?;
    assert!(parameters
        .iter()
        .any(|parameter| parameter["name"] == "searchValue"));
    assert!(parameters
        .iter()
        .any(|parameter| parameter["name"] == "filterOperator"));
    assert_eq!(
        list_users["responses"]["200"]["content"]["application/json"]["schema"]["properties"]
            ["users"]["items"]["$ref"],
        "#/components/schemas/User"
    );

    let impersonate = &openapi["paths"]["/admin/impersonate-user"]["post"];
    assert_eq!(impersonate["operationId"], "impersonateUser");
    assert_eq!(
        impersonate["responses"]["200"]["content"]["application/json"]["schema"]["properties"]
            ["session"]["$ref"],
        "#/components/schemas/Session"
    );
    Ok(())
}

fn secret() -> String {
    "secret-a-at-least-32-chars-long!!".to_owned()
}