Create user using kanidm
This commit is contained in:
parent
918a906b64
commit
edcce5e05b
4
.env
4
.env
@ -7,7 +7,7 @@ ORDER_DATABASE_URL=postgres://postgres@localhost/myco_orders
|
|||||||
TOKEN_DATABASE_URL=postgres://postgres@localhost/myco_tokens
|
TOKEN_DATABASE_URL=postgres://postgres@localhost/myco_tokens
|
||||||
|
|
||||||
PASS_SALT=18CHwV7eGFAea16z+qMKZg
|
PASS_SALT=18CHwV7eGFAea16z+qMKZg
|
||||||
RUST_LOG=debug
|
RUST_LOG=hyper=error,debug
|
||||||
SESSION_SECRET="NEPJs#8jjn8SK8GC7QEC^*P844UgsyEbQB8mRWXkT%3mPrwewZoc25MMby9H#R*w2KzaQgMkk#Pif$kxrLy*N5L!Ch%jxbWoa%gb"
|
SESSION_SECRET="NEPJs#8jjn8SK8GC7QEC^*P844UgsyEbQB8mRWXkT%3mPrwewZoc25MMby9H#R*w2KzaQgMkk#Pif$kxrLy*N5L!Ch%jxbWoa%gb"
|
||||||
JWT_SECRET="42^iFq&ZnQbUf!hwGWXd&CpyY6QQyJmkPU%esFCvne5&Ejcb3nJ4&GyHZp!MArZLf^9*5c6!!VgM$iZ8T%d#&bWTi&xbZk2S@4RN"
|
JWT_SECRET="42^iFq&ZnQbUf!hwGWXd&CpyY6QQyJmkPU%esFCvne5&Ejcb3nJ4&GyHZp!MArZLf^9*5c6!!VgM$iZ8T%d#&bWTi&xbZk2S@4RN"
|
||||||
SIGNATURE=David
|
SIGNATURE=David
|
||||||
@ -38,3 +38,5 @@ SONIC_SEARCH_PASS=SecretPassword
|
|||||||
SONIC_INGEST_ADDR=[::1]:1491
|
SONIC_INGEST_ADDR=[::1]:1491
|
||||||
SONIC_INGEST_PASS=SecretPassword
|
SONIC_INGEST_PASS=SecretPassword
|
||||||
SEARCH_ACTIVE=true
|
SEARCH_ACTIVE=true
|
||||||
|
|
||||||
|
KANIDM_IDM_ADMIN_PASS=2MScM5Cr2ANyLRps4ccGZjSJdx8bth6yXEwKJDqYU5ZdNfKN
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ web/dist
|
|||||||
web/tmp
|
web/tmp
|
||||||
adapters
|
adapters
|
||||||
plugins
|
plugins
|
||||||
|
.env
|
||||||
|
758
Cargo.lock
generated
758
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@ members = [
|
|||||||
"crates/testx",
|
"crates/testx",
|
||||||
"crates/db-utils",
|
"crates/db-utils",
|
||||||
# actors
|
# actors
|
||||||
# "crates/account_manager",
|
"crates/account_manager",
|
||||||
# "crates/cart_manager",
|
# "crates/cart_manager",
|
||||||
# "crates/database_manager",
|
# "crates/database_manager",
|
||||||
# "crates/email_manager",
|
# "crates/email_manager",
|
||||||
|
@ -53,7 +53,6 @@ db_path = "/data/kanidm.db"
|
|||||||
|
|
||||||
tls_chain = "/data/ca.pem"
|
tls_chain = "/data/ca.pem"
|
||||||
tls_key = "/data/ca.key"
|
tls_key = "/data/ca.key"
|
||||||
verify_ca = false
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# The log level of the server. May be one of info, debug, trace
|
# The log level of the server. May be one of info, debug, trace
|
||||||
@ -61,7 +60,7 @@ verify_ca = false
|
|||||||
# NOTE: this can be overridden by the environment variable
|
# NOTE: this can be overridden by the environment variable
|
||||||
# `KANIDM_LOG_LEVEL` at runtime
|
# `KANIDM_LOG_LEVEL` at runtime
|
||||||
# Defaults to "info"
|
# Defaults to "info"
|
||||||
# log_level = "info"
|
log_level = "info"
|
||||||
#
|
#
|
||||||
# The DNS domain name of the server. This is used in a
|
# The DNS domain name of the server. This is used in a
|
||||||
# number of security-critical contexts
|
# number of security-critical contexts
|
||||||
|
@ -16,6 +16,8 @@ dotenv = { version = "0" }
|
|||||||
futures = { version = "0" }
|
futures = { version = "0" }
|
||||||
gumdrop = { version = "0" }
|
gumdrop = { version = "0" }
|
||||||
json = { version = "0" }
|
json = { version = "0" }
|
||||||
|
kanidm_client = "1.2.2"
|
||||||
|
kanidm_proto = "1.2.2"
|
||||||
model = { path = "../model", features = ['db'] }
|
model = { path = "../model", features = ['db'] }
|
||||||
rumqttc = { version = "*" }
|
rumqttc = { version = "*" }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
@ -25,6 +27,7 @@ tarpc = { version = "0", features = ["tokio1", "serde-transport-bincode", "serde
|
|||||||
thiserror = { version = "1" }
|
thiserror = { version = "1" }
|
||||||
tokio = { version = "1", features = ['full'] }
|
tokio = { version = "1", features = ['full'] }
|
||||||
tracing = { version = "0" }
|
tracing = { version = "0" }
|
||||||
|
uuid = { workspace = true, features = ["v4"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
fake = { version = "2" }
|
fake = { version = "2" }
|
||||||
|
@ -4,8 +4,7 @@ pub mod addresses;
|
|||||||
pub use accounts::*;
|
pub use accounts::*;
|
||||||
pub use addresses::*;
|
pub use addresses::*;
|
||||||
use config::SharedAppConfig;
|
use config::SharedAppConfig;
|
||||||
use sqlx_core::pool::Pool;
|
use sqlx::{Pool, Postgres};
|
||||||
use sqlx_core::postgres::Postgres;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
|
126
crates/account_manager/src/idp.rs
Normal file
126
crates/account_manager/src/idp.rs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
use kanidm_client::{ClientError, KanidmClient};
|
||||||
|
use kanidm_proto::internal::CUStatus;
|
||||||
|
use kanidm_proto::v1::Entry;
|
||||||
|
|
||||||
|
pub async fn refresh_token(kanidm: &KanidmClient) -> Result<(), ClientError> {
|
||||||
|
kanidm
|
||||||
|
.auth_simple_password(
|
||||||
|
"idm_admin",
|
||||||
|
&std::env::var("KANIDM_IDM_ADMIN_PASS")
|
||||||
|
.expect("idm_admin password is requied, please set KANIDM_IDM_ADMIN_PASS"),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_account_with_password(
|
||||||
|
kanidm: &KanidmClient,
|
||||||
|
login: &str,
|
||||||
|
display_name: &str,
|
||||||
|
email: &str,
|
||||||
|
password: &str,
|
||||||
|
) -> Result<(), ClientError> {
|
||||||
|
refresh_token(kanidm).await?;
|
||||||
|
let _person_created = kanidm
|
||||||
|
.idm_person_account_create(login, display_name)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
let accounts = accounts(kanidm).await?;
|
||||||
|
let uid = find_account(&accounts, FindBy::Name(login)).await?;
|
||||||
|
let id = uid.to_string();
|
||||||
|
|
||||||
|
kanidm
|
||||||
|
.idm_person_account_update(&id, None, None, None, Some(&[email.to_string()]))
|
||||||
|
.await?;
|
||||||
|
let (session_token, status) = kanidm.idm_account_credential_update_begin(&id).await?;
|
||||||
|
tracing::debug!(
|
||||||
|
"Begin update credentials ({can_commit}): {status:?}",
|
||||||
|
can_commit = status.can_commit
|
||||||
|
);
|
||||||
|
|
||||||
|
kanidm
|
||||||
|
.idm_account_credential_update_set_password(&session_token, password)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let status = kanidm
|
||||||
|
.idm_account_credential_update_status(&session_token)
|
||||||
|
.await?;
|
||||||
|
tracing::debug!(
|
||||||
|
"Set password ({can_commit}): {status:?}",
|
||||||
|
can_commit = status.can_commit
|
||||||
|
);
|
||||||
|
|
||||||
|
let status = kanidm
|
||||||
|
.idm_account_credential_update_init_totp(&session_token)
|
||||||
|
.await?;
|
||||||
|
tracing::debug!(
|
||||||
|
"Init TOTP ({can_commit}): {status:?}",
|
||||||
|
can_commit = status.can_commit
|
||||||
|
);
|
||||||
|
|
||||||
|
// let status = kanidm
|
||||||
|
// .idm_account_credential_update_check_totp(&session_token, totp_chal,
|
||||||
|
// label) .await?;
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"TOTP check ({can_commit}): {status:?}",
|
||||||
|
can_commit = status.can_commit
|
||||||
|
);
|
||||||
|
|
||||||
|
kanidm
|
||||||
|
.idm_account_credential_update_commit(&session_token)
|
||||||
|
.await?;
|
||||||
|
let status = kanidm
|
||||||
|
.idm_account_credential_update_status(&session_token)
|
||||||
|
.await?;
|
||||||
|
tracing::debug!(
|
||||||
|
"Commit ({can_commit}): {status:?}",
|
||||||
|
can_commit = status.can_commit
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn accounts(kanidm: &KanidmClient) -> Result<Vec<Entry>, ClientError> {
|
||||||
|
refresh_token(kanidm).await?;
|
||||||
|
|
||||||
|
kanidm.idm_person_account_list().await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FindBy<'s> {
|
||||||
|
Email(&'s str),
|
||||||
|
Name(&'s str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> FindBy<'s> {
|
||||||
|
fn key(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Email(..) => "mail",
|
||||||
|
Self::Name(..) => "name",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn as_str(&self) -> &'s str {
|
||||||
|
match self {
|
||||||
|
Self::Email(s) => s,
|
||||||
|
Self::Name(s) => s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find_account(list: &[Entry], find_by: FindBy<'_>) -> Result<uuid::Uuid, ClientError> {
|
||||||
|
list.iter()
|
||||||
|
.find_map(|entra| {
|
||||||
|
tracing::debug!("compare {find_by:?} with {entra:?}");
|
||||||
|
let attrs = &entra.attrs;
|
||||||
|
attrs.get(find_by.key()).filter(|v| {
|
||||||
|
tracing::debug!("compare value {v:?} with {s}", s = find_by.as_str());
|
||||||
|
v.iter().any(|s| s == find_by.as_str())
|
||||||
|
})?;
|
||||||
|
let id = attrs.get("uuid").and_then(|v| v.first())?;
|
||||||
|
id.parse::<uuid::Uuid>().ok()
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
|
tracing::info!("User not found");
|
||||||
|
ClientError::Unauthorized
|
||||||
|
})
|
||||||
|
}
|
@ -4,6 +4,7 @@ use config::UpdateConfig;
|
|||||||
|
|
||||||
pub mod actions;
|
pub mod actions;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
pub mod idp;
|
||||||
pub mod mqtt;
|
pub mod mqtt;
|
||||||
pub mod rpc;
|
pub mod rpc;
|
||||||
|
|
||||||
@ -38,6 +39,23 @@ async fn main() {
|
|||||||
|
|
||||||
let db = db::Database::build(config.clone()).await;
|
let db = db::Database::build(config.clone()).await;
|
||||||
|
|
||||||
|
let kanidm = kanidm_client::KanidmClientBuilder::new()
|
||||||
|
.address(config.lock().account_manager().idm_url().to_owned())
|
||||||
|
.danger_accept_invalid_certs(cfg!(debug_assertions))
|
||||||
|
.connect_timeout(2)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
idp::accounts(&kanidm).await.unwrap();
|
||||||
|
idp::create_account_with_password(
|
||||||
|
&kanidm,
|
||||||
|
"eraden",
|
||||||
|
"Adrian Woźniak",
|
||||||
|
"adrian.wozniak@ita-prog.pl",
|
||||||
|
"n59GmOOdcpVUJqJ1",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mqtt_client = mqtt::start(config.clone(), db.clone()).await;
|
let mqtt_client = mqtt::start(config.clone(), db.clone()).await;
|
||||||
rpc::start(config.clone(), db.clone(), mqtt_client.clone()).await;
|
rpc::start(config.clone(), db.clone(), mqtt_client.clone()).await;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ struct AccountsServer {
|
|||||||
mqtt_client: AsyncClient,
|
mqtt_client: AsyncClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tarpc::server]
|
|
||||||
impl Accounts for AccountsServer {
|
impl Accounts for AccountsServer {
|
||||||
async fn me(self, _: context::Context, input: me::Input) -> me::Output {
|
async fn me(self, _: context::Context, input: me::Input) -> me::Output {
|
||||||
let res = actions::me(input.account_id, self.db).await;
|
let res = actions::me(input.account_id, self.db).await;
|
||||||
|
@ -8,10 +8,9 @@ use tarpc::tokio_serde::formats::Bincode;
|
|||||||
|
|
||||||
pub async fn start<Server, Req, Build>(name: &str, port: u16, build: Build)
|
pub async fn start<Server, Req, Build>(name: &str, port: u16, build: Build)
|
||||||
where
|
where
|
||||||
Server: Serve<Req> + Send + 'static + Clone,
|
Server: Serve<Req = Req> + Send + 'static + Clone,
|
||||||
Build: Fn() -> Server,
|
Build: Fn() -> Server,
|
||||||
<Server as Serve<Req>>::Fut: Send,
|
Server::Resp: serde::Serialize + Send + 'static,
|
||||||
<Server as Serve<Req>>::Resp: serde::Serialize + Send + 'static,
|
|
||||||
Req: Send + 'static,
|
Req: Send + 'static,
|
||||||
Req: for<'l> serde::Deserialize<'l>,
|
Req: for<'l> serde::Deserialize<'l>,
|
||||||
{
|
{
|
||||||
@ -33,7 +32,7 @@ where
|
|||||||
// the generated World trait.
|
// the generated World trait.
|
||||||
.map(|channel| channel.execute(build()))
|
.map(|channel| channel.execute(build()))
|
||||||
// Max 10 channels.
|
// Max 10 channels.
|
||||||
.buffer_unordered(10)
|
// .buffer_unordered(10)
|
||||||
.for_each(|_| async {})
|
.for_each(|_| async {})
|
||||||
.await;
|
.await;
|
||||||
tracing::info!("RPC channel closed");
|
tracing::info!("RPC channel closed");
|
||||||
|
@ -354,6 +354,7 @@ pub struct AccountManagerConfig {
|
|||||||
pub mqtt_port: u16,
|
pub mqtt_port: u16,
|
||||||
pub mqtt_bind: String,
|
pub mqtt_bind: String,
|
||||||
pub database_url: String,
|
pub database_url: String,
|
||||||
|
pub idm_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AccountManagerConfig {
|
impl Default for AccountManagerConfig {
|
||||||
@ -364,6 +365,7 @@ impl Default for AccountManagerConfig {
|
|||||||
mqtt_port: 1883,
|
mqtt_port: 1883,
|
||||||
mqtt_bind: "0.0.0.0".into(),
|
mqtt_bind: "0.0.0.0".into(),
|
||||||
database_url: "postgres://postgres@localhost/myco_accounts".into(),
|
database_url: "postgres://postgres@localhost/myco_accounts".into(),
|
||||||
|
idm_url: "https://localhost:8443".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,6 +380,10 @@ impl AccountManagerConfig {
|
|||||||
pub fn mqtt_addr(&self) -> (&str, u16) {
|
pub fn mqtt_addr(&self) -> (&str, u16) {
|
||||||
(&self.mqtt_bind, self.mqtt_port)
|
(&self.mqtt_bind, self.mqtt_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn idm_url(&self) -> &str {
|
||||||
|
&self.idm_url
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -149,7 +149,7 @@ impl From<(crate::Order, Vec<crate::OrderItem>)> for Order {
|
|||||||
checkout_notes,
|
checkout_notes,
|
||||||
address_id,
|
address_id,
|
||||||
},
|
},
|
||||||
mut items,
|
items,
|
||||||
): (crate::Order, Vec<crate::OrderItem>),
|
): (crate::Order, Vec<crate::OrderItem>),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Order {
|
Order {
|
||||||
|
@ -10,7 +10,13 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 636:3636
|
- 636:3636
|
||||||
- 443:8443
|
- 443:8443
|
||||||
|
- 8443:8443
|
||||||
- 8400:80
|
- 8400:80
|
||||||
|
rumqqtd:
|
||||||
|
image: bytebeamio/rumqttd
|
||||||
|
ports:
|
||||||
|
- 1883:1883
|
||||||
|
- 1884:1884
|
||||||
quickwit:
|
quickwit:
|
||||||
image: quickwit/quickwit:v0.5.2
|
image: quickwit/quickwit:v0.5.2
|
||||||
command: run
|
command: run
|
||||||
|
90
myco.toml
Normal file
90
myco.toml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
[account_manager]
|
||||||
|
rpc_port = 19329
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1883
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_accounts"
|
||||||
|
idm_url = "https://localhost:8443"
|
||||||
|
|
||||||
|
[cart_manager]
|
||||||
|
rpc_port = 19330
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1884
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_carts"
|
||||||
|
|
||||||
|
[database]
|
||||||
|
url = "postgres://postgres@localhost/myco"
|
||||||
|
|
||||||
|
[email_sender]
|
||||||
|
rpc_port = 19331
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1885
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_emails"
|
||||||
|
|
||||||
|
[files]
|
||||||
|
public_path = "/uploads"
|
||||||
|
local_path = "/var/local/myco"
|
||||||
|
|
||||||
|
[mail]
|
||||||
|
sendgrid_secret = "Create sendgrid account and copy credentials here"
|
||||||
|
sendgrid_api_key = "Create sendgrid account and copy credentials here"
|
||||||
|
smtp_from = "Valid sendgrid authorized email address. Example: contact@example.com"
|
||||||
|
|
||||||
|
[order_manager]
|
||||||
|
rpc_port = 19334
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1887
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_orders"
|
||||||
|
|
||||||
|
[payment]
|
||||||
|
rpc_port = 19335
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1888
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
adapters_path = "./adapters"
|
||||||
|
optional_payment = true
|
||||||
|
|
||||||
|
[payment.pay_u]
|
||||||
|
client_id = "Create payu account and copy here client_id"
|
||||||
|
client_secret = "Create payu account and copy here client_secret"
|
||||||
|
merchant_id = "Create payu account and copy here merchant id"
|
||||||
|
example2 = "custom value2"
|
||||||
|
example1 = "custom value1"
|
||||||
|
|
||||||
|
[search]
|
||||||
|
sonic_search_addr = "[::1]:1491"
|
||||||
|
sonic_search_pass = "SecretPassword"
|
||||||
|
sonic_ingest_addr = "[::1]:1491"
|
||||||
|
sonic_ingest_pass = "SecretPassword"
|
||||||
|
rpc_port = 19332
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
search_active = true
|
||||||
|
|
||||||
|
[stocks]
|
||||||
|
rpc_port = 19333
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1886
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_stocks"
|
||||||
|
|
||||||
|
[tokens]
|
||||||
|
rpc_port = 19336
|
||||||
|
rpc_bind = "0.0.0.0"
|
||||||
|
mqtt_port = 1889
|
||||||
|
mqtt_bind = "0.0.0.0"
|
||||||
|
database_url = "postgres://postgres@localhost/myco_tokens"
|
||||||
|
|
||||||
|
[web]
|
||||||
|
host = "https://your.comain.com"
|
||||||
|
pass_salt = "Generate it with myco generate-hash"
|
||||||
|
session_secret = "100 characters long random string"
|
||||||
|
jwt_secret = "100 characters long random string"
|
||||||
|
bind = "0.0.0.0"
|
||||||
|
port = 8080
|
||||||
|
signature = "John Doe"
|
||||||
|
service_name = "myco"
|
||||||
|
|
||||||
|
[plugin]
|
Loading…
Reference in New Issue
Block a user