#![allow(clippy::all, unused_imports, dead_code)]
use crate::{Actor, ActorBehavior, ClientBuilderExt, Message, Port};
use anyhow::{Error, Result};
use reflow_actor::{message::EncodableValue, ActorContext};
use reflow_actor_macro::actor;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::time::Duration;
const BASE_URL: &str = "https://{domain}.auth0.com/api/v2";
const ENV_KEY: &str = "AUTH0_API_KEY";
fn apply_auth(
config: &reflow_actor::ActorConfig,
mut builder: reqwest::RequestBuilder,
) -> Result<reqwest::RequestBuilder> {
let credential = config
.get_config_or_env(ENV_KEY)
.ok_or_else(|| anyhow::anyhow!("Missing env var: {}", ENV_KEY))?;
builder = builder.header("Authorization", format!("Bearer {}", credential));
Ok(builder)
}
#[actor(
Auth0CreateUserActor,
inports::<100>(email, password, connection),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_user(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/users".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("email") {
body.insert("email".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("password") {
body.insert("password".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("connection") {
body.insert("connection".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /users failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ReadUserActor,
inports::<100>(id),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_read_user(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/users/{id}".to_string();
if let Some(val) = inputs.get("id") {
endpoint = endpoint.replace("{{id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /users/{{id}} failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListUsersActor,
inports::<100>(q, page),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_users(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/users".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("q") {
query_pairs.push(("q", super::message_to_str(val)));
}
if let Some(val) = inputs.get("page") {
query_pairs.push(("page", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /users failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListAuthorizeUserActor,
inports::<100>(audience, scope, response_type, client_id, redirect_uri, state, nonce, code_challenge_method, code_challenge, connection, prompt, organization, invitation),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_authorize_user(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/authorize".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("audience") {
query_pairs.push(("audience", super::message_to_str(val)));
}
if let Some(val) = inputs.get("scope") {
query_pairs.push(("scope", super::message_to_str(val)));
}
if let Some(val) = inputs.get("response_type") {
query_pairs.push(("response_type", super::message_to_str(val)));
}
if let Some(val) = inputs.get("client_id") {
query_pairs.push(("client_id", super::message_to_str(val)));
}
if let Some(val) = inputs.get("redirect_uri") {
query_pairs.push(("redirect_uri", super::message_to_str(val)));
}
if let Some(val) = inputs.get("state") {
query_pairs.push(("state", super::message_to_str(val)));
}
if let Some(val) = inputs.get("nonce") {
query_pairs.push(("nonce", super::message_to_str(val)));
}
if let Some(val) = inputs.get("code_challenge_method") {
query_pairs.push(("code_challenge_method", super::message_to_str(val)));
}
if let Some(val) = inputs.get("code_challenge") {
query_pairs.push(("code_challenge", super::message_to_str(val)));
}
if let Some(val) = inputs.get("connection") {
query_pairs.push(("connection", super::message_to_str(val)));
}
if let Some(val) = inputs.get("prompt") {
query_pairs.push(("prompt", super::message_to_str(val)));
}
if let Some(val) = inputs.get("organization") {
query_pairs.push(("organization", super::message_to_str(val)));
}
if let Some(val) = inputs.get("invitation") {
query_pairs.push(("invitation", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /authorize failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateDbConnectionsActor,
inports::<100>(client_id, connection, email, organization),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_db_connections(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/dbconnections/change_password".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("client_id") {
body.insert("client_id".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("connection") {
body.insert("connection".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("email") {
body.insert("email".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("organization") {
body.insert("organization".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /dbconnections/change_password failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateSsoActor,
inports::<100>(connection, SAMLResponse),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_sso(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/login/callback".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("connection") {
query_pairs.push(("connection", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("SAMLResponse") {
body.insert("SAMLResponse".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /login/callback failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateMfaActor,
inports::<100>(client_id, client_assertion, client_assertion_type, client_secret, authenticator_types, phone_number, oob_channels),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_mfa(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/mfa/associate".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("client_id") {
body.insert("client_id".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion") {
body.insert("client_assertion".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion_type") {
body.insert("client_assertion_type".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_secret") {
body.insert("client_secret".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("authenticator_types") {
body.insert("authenticator_types".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("phone_number") {
body.insert("phone_number".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("oob_channels") {
body.insert("oob_channels".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /mfa/associate failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListMfaActor,
inports::<100>(ACCESS_TOKEN),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_mfa(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/mfa/authenticators".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
if let Some(val) = inputs.get("ACCESS_TOKEN") {
builder = builder.header("ACCESS_TOKEN", super::message_to_str(val));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /mfa/authenticators failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0DeleteMfaActor,
inports::<100>(ACCESS_TOKEN, AUTHENTICATOR_ID),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_delete_mfa(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/mfa/authenticators/{AUTHENTICATOR_ID}".to_string();
if let Some(val) = inputs.get("AUTHENTICATOR_ID") {
endpoint = endpoint.replace("{{AUTHENTICATOR_ID}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.delete(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
if let Some(val) = inputs.get("ACCESS_TOKEN") {
builder = builder.header("ACCESS_TOKEN", super::message_to_str(val));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"DELETE /mfa/authenticators/{{AUTHENTICATOR_ID}} failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateDeviceFlowActor,
inports::<100>(scope, client_id, audience),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_device_flow(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/oauth/device/code".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("scope") {
body.insert("scope".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_id") {
body.insert("client_id".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("audience") {
body.insert("audience".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /oauth/device/code failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateRevokeRefreshTokenActor,
inports::<100>(client_id, client_assertion, client_assertion_type, token, client_secret),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_revoke_refresh_token(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/oauth/revoke".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("client_id") {
body.insert("client_id".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion") {
body.insert("client_assertion".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion_type") {
body.insert("client_assertion_type".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("token") {
body.insert("token".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_secret") {
body.insert("client_secret".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /oauth/revoke failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateOauthTokenActor,
inports::<100>(auth0_forwarded_for),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_oauth_token(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/oauth/token".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
if let Some(val) = inputs.get("auth0_forwarded_for") {
builder = builder.header("auth0-forwarded-for", super::message_to_str(val));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /oauth/token failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListLogoutActor,
inports::<100>(id_token_hint, logout_hint, post_logout_redirect_uri, client_id, federated, state, ui_locales),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_logout(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/oidc/logout".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("id_token_hint") {
query_pairs.push(("id_token_hint", super::message_to_str(val)));
}
if let Some(val) = inputs.get("logout_hint") {
query_pairs.push(("logout_hint", super::message_to_str(val)));
}
if let Some(val) = inputs.get("post_logout_redirect_uri") {
query_pairs.push(("post_logout_redirect_uri", super::message_to_str(val)));
}
if let Some(val) = inputs.get("client_id") {
query_pairs.push(("client_id", super::message_to_str(val)));
}
if let Some(val) = inputs.get("federated") {
query_pairs.push(("federated", super::message_to_str(val)));
}
if let Some(val) = inputs.get("state") {
query_pairs.push(("state", super::message_to_str(val)));
}
if let Some(val) = inputs.get("ui_locales") {
query_pairs.push(("ui_locales", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /oidc/logout failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateOidcActor,
inports::<100>(client_name, redirect_uris, token_endpoint_auth_method),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_oidc(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/oidc/register".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("client_name") {
body.insert("client_name".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("redirect_uris") {
body.insert("redirect_uris".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("token_endpoint_auth_method") {
body.insert("token_endpoint_auth_method".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /oidc/register failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0StartPasswordlessActor,
inports::<100>(client_id, client_secret, phone_number, client_assertion_type, authParams, email, send, client_assertion, connection),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_start_passwordless(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/passwordless/start".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("client_id") {
body.insert("client_id".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_secret") {
body.insert("client_secret".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("phone_number") {
body.insert("phone_number".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion_type") {
body.insert("client_assertion_type".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("authParams") {
body.insert("authParams".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("email") {
body.insert("email".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("send") {
body.insert("send".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("client_assertion") {
body.insert("client_assertion".to_string(), val.clone().into());
}
if let Some(val) = inputs.get("connection") {
body.insert("connection".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /passwordless/start failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ReadSamlActor,
inports::<100>(client_id),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_read_saml(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/samlp/metadata/{client_id}".to_string();
if let Some(val) = inputs.get("client_id") {
endpoint = endpoint.replace("{{client_id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /samlp/metadata/{{client_id}} failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0CreateLogoutActor,
inports::<100>(CLIENT_ID, body),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_create_logout(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/samlp/{CLIENT_ID}/logout".to_string();
if let Some(val) = inputs.get("CLIENT_ID") {
endpoint = endpoint.replace("{{CLIENT_ID}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.post(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut body = serde_json::Map::new();
if let Some(val) = inputs.get("body") {
body.insert("body".to_string(), val.clone().into());
}
if !body.is_empty() {
builder = builder.json(&serde_json::Value::Object(body));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("POST /samlp/{{CLIENT_ID}}/logout failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListUserProfileActor,
inports::<100>(access_token),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_user_profile(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/userinfo".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
if let Some(val) = inputs.get("access_token") {
builder = builder.header("access_token", super::message_to_str(val));
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /userinfo failed: {}", e).into()),
);
}
}
Ok(output)
}
#[actor(
Auth0ListWsFedActor,
inports::<100>(trigger),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_list_ws_fed(context: ActorContext) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let endpoint = "/wsfed/FederationMetadata/2007-06/FederationMetadata.xml".to_string();
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(
format!(
"GET /wsfed/FederationMetadata/2007-06/FederationMetadata.xml failed: {}",
e
)
.into(),
),
);
}
}
Ok(output)
}
#[actor(
Auth0ReadWsFederationActor,
inports::<100>(client_id, wtrealm, whr, wctx, wreply),
outports::<50>(response, error),
state(MemoryState)
)]
pub async fn auth0_read_ws_federation(
context: ActorContext,
) -> Result<HashMap<String, Message>, Error> {
let inputs = context.get_payload();
let actor_config = context.get_config();
let mut endpoint = "/wsfed/{client_id}".to_string();
if let Some(val) = inputs.get("client_id") {
endpoint = endpoint.replace("{{client_id}}", &super::message_to_str(val));
}
let url = format!("{}{}", BASE_URL.trim_end_matches('/'), endpoint);
let client = reqwest::Client::builder()
.timeout_compat(Duration::from_secs(30))
.build()?;
let mut builder = client.get(&url);
builder = builder.header("Content-Type", "application/json");
builder = apply_auth(actor_config, builder)?;
let mut query_pairs: Vec<(&str, String)> = Vec::new();
if let Some(val) = inputs.get("wtrealm") {
query_pairs.push(("wtrealm", super::message_to_str(val)));
}
if let Some(val) = inputs.get("whr") {
query_pairs.push(("whr", super::message_to_str(val)));
}
if let Some(val) = inputs.get("wctx") {
query_pairs.push(("wctx", super::message_to_str(val)));
}
if let Some(val) = inputs.get("wreply") {
query_pairs.push(("wreply", super::message_to_str(val)));
}
if !query_pairs.is_empty() {
builder = builder.query(&query_pairs);
}
let mut output = HashMap::new();
match builder.send().await {
Ok(resp) => {
let status = resp.status().as_u16();
let headers: HashMap<String, String> = resp
.headers()
.iter()
.filter_map(|(k, v)| v.to_str().ok().map(|val| (k.to_string(), val.to_string())))
.collect();
let body_text = resp.text().await.unwrap_or_default();
let body_value: Value =
serde_json::from_str(&body_text).unwrap_or(Value::String(body_text));
output.insert(
"response".to_string(),
Message::object(EncodableValue::from(json!({
"status": status,
"headers": headers,
"body": body_value,
}))),
);
}
Err(e) => {
output.insert(
"error".to_string(),
Message::Error(format!("GET /wsfed/{{client_id}} failed: {}", e).into()),
);
}
}
Ok(output)
}