feat: sso saml admin placeholders

This commit is contained in:
Fu Zi Xiang 2023-11-27 15:45:10 +08:00
parent 661c6d7370
commit c35e121ccf
No known key found for this signature in database
9 changed files with 160 additions and 1 deletions

View File

@ -1,6 +1,12 @@
use askama::Template;
use gotrue_entity::dto::User;
#[derive(Template)]
#[template(path = "components/admin_sso_list.html")]
pub struct SsoList {
// TODO
}
#[derive(Template)]
#[template(path = "components/change_password.html")]
pub struct ChangePassword;

View File

@ -35,6 +35,12 @@ pub fn component_router() -> Router<AppState> {
.route("/admin/users", get(admin_users_handler))
.route("/admin/users/:user_id", get(admin_user_details_handler))
.route("/admin/users/create", get(admin_users_create_handler))
// SSO
.route("/admin/sso", get(admin_sso_handler))
}
pub async fn admin_sso_handler() -> Result<Html<String>, WebAppError> {
render_template(templates::SsoList {})
}
pub async fn user_navigate_handler() -> Result<Html<String>, WebAppError> {

View File

@ -22,4 +22,18 @@
>
Create User
</div>
<div
class="sidebar-item"
hx-target="#sidebar-content"
hx-get="/web/components/admin/sso"
>
List SSO
</div>
<div
class="sidebar-item"
hx-target="#sidebar-content"
hx-get="/web/components/admin/sso/create"
>
Create SSO
</div>
</div>

View File

@ -0,0 +1,3 @@
<div>
<!--> TODO <-->
</div>

5
doc/OKTA_SAML.md Normal file
View File

@ -0,0 +1,5 @@
# Okta Authentication via SAML
- Guide for adding AppFlowy to [Okta](https://www.okta.com)
- This guide assumes the following
- You are an Admin of Okta Identity Provider
- You have AppFlowy-Cloud deployed [Deployment](./DEPLOYMENT.md)

View File

@ -3,3 +3,4 @@ pub mod error {
pub use app_error::gotrue::*;
}
pub mod gotrue_jwt;
pub mod sso;

View File

@ -0,0 +1,41 @@
use std::collections::BTreeMap;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct SSOProviders {
pub items: Vec<SSOProvider>,
}
#[derive(Debug, Deserialize)]
pub struct SSOProvider {
pub id: String,
pub saml: SAMLProvider,
pub domains: Vec<String>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Deserialize)]
pub struct SAMLProvider {
pub entity_id: String,
pub metadata_xml: Option<String>,
pub metadata_url: Option<String>,
pub attribute_mapping: SAMLAttributeMapping,
}
#[derive(Debug, Deserialize)]
pub struct SAMLAttributeMapping {
pub keys: Option<BTreeMap<String, SAMLAttribute>>,
}
#[derive(Debug, Deserialize)]
pub struct SAMLAttribute {
pub name: Option<String>,
pub names: Option<Vec<String>>,
pub default: serde_json::Value,
}
pub struct SSODomain {
pub domain: String,
}

View File

@ -1,6 +1,7 @@
use super::grant::Grant;
use crate::params::{
AdminDeleteUserParams, AdminUserParams, GenerateLinkParams, GenerateLinkResponse, MagicLinkParams,
AdminDeleteUserParams, AdminUserParams, CreateSSOProviderParams, GenerateLinkParams,
GenerateLinkResponse, MagicLinkParams,
};
use anyhow::Context;
use gotrue_entity::dto::{
@ -8,6 +9,7 @@ use gotrue_entity::dto::{
UpdateGotrueUserParams, User,
};
use gotrue_entity::error::{GoTrueError, GoTrueErrorSerde, GotrueClientError};
use gotrue_entity::sso::{SSOProvider, SSOProviders};
use infra::reqwest::{check_response, from_body, from_response};
#[derive(Clone)]
@ -235,6 +237,78 @@ impl Client {
.await?;
check_gotrue_result(resp).await
}
pub async fn admin_list_sso_providers(
&self,
access_token: &str,
) -> Result<SSOProviders, GoTrueError> {
let resp = self
.client
.get(format!("{}/admin/sso/providers", self.base_url))
.header("Authorization", format!("Bearer {}", access_token))
.send()
.await?;
to_gotrue_result(resp).await
}
pub async fn admin_create_sso_providers(
&self,
access_token: &str,
create_sso_provider_params: &CreateSSOProviderParams,
) -> Result<SSOProvider, GoTrueError> {
let resp = self
.client
.post(format!("{}/admin/sso/providers", self.base_url))
.header("Authorization", format!("Bearer {}", access_token))
.json(create_sso_provider_params)
.send()
.await?;
to_gotrue_result(resp).await
}
pub async fn admin_get_sso_provider(
&self,
access_token: &str,
idp_id: &str,
) -> Result<SSOProvider, GoTrueError> {
let resp = self
.client
.get(format!("{}/admin/sso/providers/{}", self.base_url, idp_id))
.header("Authorization", format!("Bearer {}", access_token))
.send()
.await?;
to_gotrue_result(resp).await
}
pub async fn admin_update_sso_provider(
&self,
access_token: &str,
idp_id: &str,
create_sso_provider_params: &CreateSSOProviderParams,
) -> Result<SSOProvider, GoTrueError> {
let resp = self
.client
.put(format!("{}/admin/sso/providers/{}", self.base_url, idp_id))
.header("Authorization", format!("Bearer {}", access_token))
.json(create_sso_provider_params)
.send()
.await?;
to_gotrue_result(resp).await
}
pub async fn admin_delete_sso_provider(
&self,
access_token: &str,
idp_id: &str,
) -> Result<SSOProvider, GoTrueError> {
let resp = self
.client
.delete(format!("{}/admin/sso/providers/{}", self.base_url, idp_id))
.header("Authorization", format!("Bearer {}", access_token))
.send()
.await?;
to_gotrue_result(resp).await
}
}
async fn to_gotrue_result<T>(resp: reqwest::Response) -> Result<T, GoTrueError>

View File

@ -105,3 +105,12 @@ pub struct GenerateLinkResponse {
pub verification_type: String,
pub redirect_to: String,
}
#[derive(Debug, Serialize, Default)]
pub struct CreateSSOProviderParams {
pub type_: String,
pub metadata_url: String,
pub metadata_xml: String,
pub domains: Vec<String>,
pub attribute_mapping: serde_json::Value,
}