ockam_api 0.48.0

Ockam's request-response API
Documentation
use crate::cloud::enroll::auth0::{AuthenticateOidcToken, OidcToken};
use crate::cloud::HasSecureClient;
use crate::DefaultAddress;
use miette::IntoDiagnostic;
use ockam::identity::models::CredentialAndPurposeKey;
use ockam::identity::{OneTimeCode, SecureClient};
use ockam_core::api::{Reply, Request, Status};
use ockam_core::async_trait;
use ockam_node::Context;

const TARGET: &str = "ockam_api::cloud::enroll";

pub enum EnrollStatus {
    EnrolledSuccessfully,
    AlreadyEnrolled,
    UnexpectedStatus(String, Status),
    FailedNoStatus(String),
}

#[async_trait]
pub trait Enrollment {
    async fn enroll_with_oidc_token(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<EnrollStatus>;

    async fn enroll_with_oidc_token_okta(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<()>;

    async fn present_token(&self, ctx: &Context, token: &OneTimeCode) -> miette::Result<()>;

    async fn issue_credential(&self, ctx: &Context) -> miette::Result<CredentialAndPurposeKey>;
}

#[async_trait]
impl<T: HasSecureClient + Send + Sync> Enrollment for T {
    async fn enroll_with_oidc_token(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<EnrollStatus> {
        self.get_secure_client()
            .enroll_with_oidc_token(ctx, token)
            .await
    }

    async fn enroll_with_oidc_token_okta(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<()> {
        self.get_secure_client()
            .enroll_with_oidc_token_okta(ctx, token)
            .await
    }

    async fn present_token(&self, ctx: &Context, token: &OneTimeCode) -> miette::Result<()> {
        self.get_secure_client().present_token(ctx, token).await
    }

    async fn issue_credential(&self, ctx: &Context) -> miette::Result<CredentialAndPurposeKey> {
        self.get_secure_client().issue_credential(ctx).await
    }
}

#[async_trait]
impl Enrollment for SecureClient {
    async fn enroll_with_oidc_token(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<EnrollStatus> {
        let req = Request::post("v0/enroll").body(AuthenticateOidcToken::new(token));
        trace!(target: TARGET, "executing auth0 flow");
        let reply = self
            .tell(ctx, "auth0_authenticator", req)
            .await
            .into_diagnostic()?;
        match reply {
            Reply::Successful(_) => Ok(EnrollStatus::EnrolledSuccessfully),
            Reply::Failed(_, Some(Status::BadRequest)) => Ok(EnrollStatus::AlreadyEnrolled),
            Reply::Failed(e, Some(s)) => Ok(EnrollStatus::UnexpectedStatus(e.to_string(), s)),
            Reply::Failed(e, _) => Ok(EnrollStatus::FailedNoStatus(e.to_string())),
        }
    }

    async fn enroll_with_oidc_token_okta(
        &self,
        ctx: &Context,
        token: OidcToken,
    ) -> miette::Result<()> {
        let req = Request::post("v0/enroll").body(AuthenticateOidcToken::new(token));
        trace!(target: TARGET, "executing auth0 flow");
        self.tell(ctx, DefaultAddress::OKTA_IDENTITY_PROVIDER, req)
            .await
            .into_diagnostic()?
            .success()
            .into_diagnostic()
    }

    async fn present_token(&self, ctx: &Context, token: &OneTimeCode) -> miette::Result<()> {
        let req = Request::post("/").body(token);
        trace!(target: TARGET, "present a token");
        self.tell(ctx, DefaultAddress::ENROLLMENT_TOKEN_ACCEPTOR, req)
            .await
            .into_diagnostic()?
            .success()
            .into_diagnostic()
    }

    async fn issue_credential(&self, ctx: &Context) -> miette::Result<CredentialAndPurposeKey> {
        let req = Request::post("/");
        trace!(target: TARGET, "getting a credential");
        self.ask(ctx, DefaultAddress::CREDENTIAL_ISSUER, req)
            .await
            .into_diagnostic()?
            .success()
            .into_diagnostic()
    }
}