feat/axum-0.7.x - uses breaking changes from axum 0.7.x #4
@ -6,7 +6,7 @@ use axum::http::{header::SET_COOKIE, HeaderMap};
|
||||
use oauth2::url::Url;
|
||||
|
||||
use crate::{
|
||||
introspection::IntrospectionService,
|
||||
introspection::{IdToken, IntrospectionService},
|
||||
login::{auth_clap::AuthEngine, config::ConfigClap, AuthClap},
|
||||
oauth::{zitadel::ZitadelConfig, OAuth},
|
||||
session::{SessionService, User},
|
||||
@ -15,7 +15,7 @@ use crate::{
|
||||
#[async_trait]
|
||||
pub trait Auth {
|
||||
async fn login(&self) -> anyhow::Result<Url>;
|
||||
async fn login_token(&self, user: &str, password: &str) -> anyhow::Result<String>;
|
||||
async fn login_token(&self, user: &str, password: &str) -> anyhow::Result<IdToken>;
|
||||
async fn login_authorized(&self, code: &str, state: &str) -> anyhow::Result<(HeaderMap, Url)>;
|
||||
async fn get_user_from_session(&self, cookie: &str) -> anyhow::Result<User>;
|
||||
}
|
||||
@ -86,8 +86,8 @@ impl Auth for ZitadelAuthService {
|
||||
}
|
||||
async fn login_authorized(&self, code: &str, _state: &str) -> anyhow::Result<(HeaderMap, Url)> {
|
||||
let token = self.oauth.exchange(code).await?;
|
||||
let user_id = self.introspection.get_id_token(token.as_str()).await?;
|
||||
let cookie_value = self.session.insert_user("user", user_id.as_str()).await?;
|
||||
let id_token = self.introspection.get_id_token(token.as_str()).await?;
|
||||
let cookie_value = self.session.insert_user("user", id_token).await?;
|
||||
|
||||
let cookie = format!("{}={}; SameSite=Lax; Path=/", COOKIE_NAME, cookie_value);
|
||||
|
||||
@ -100,12 +100,12 @@ impl Auth for ZitadelAuthService {
|
||||
.context("failed to parse login_authorized zitadel return url")?,
|
||||
))
|
||||
}
|
||||
async fn login_token(&self, _user: &str, password: &str) -> anyhow::Result<String> {
|
||||
async fn login_token(&self, _user: &str, password: &str) -> anyhow::Result<IdToken> {
|
||||
self.introspection.get_id_token(password).await
|
||||
}
|
||||
async fn get_user_from_session(&self, cookie: &str) -> anyhow::Result<User> {
|
||||
match self.session.get_user(cookie).await? {
|
||||
Some(u) => Ok(User { id: u }),
|
||||
Some(u) => Ok(u),
|
||||
None => Err(anyhow::anyhow!("failed to find user")),
|
||||
}
|
||||
}
|
||||
@ -126,7 +126,7 @@ impl Auth for NoopAuthService {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn login_token(&self, _user: &str, _password: &str) -> anyhow::Result<String> {
|
||||
async fn login_token(&self, _user: &str, _password: &str) -> anyhow::Result<IdToken> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,11 @@ where
|
||||
})?;
|
||||
|
||||
return Ok(UserFromSession {
|
||||
user: User { id: token },
|
||||
user: User {
|
||||
id: token.sub,
|
||||
email: token.email,
|
||||
name: token.name,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -144,8 +148,6 @@ where
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(UserFromSession {
|
||||
user: User { id: user.id },
|
||||
})
|
||||
Ok(UserFromSession { user })
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use async_trait::async_trait;
|
||||
use axum::extract::FromRef;
|
||||
use oauth2::TokenIntrospectionResponse;
|
||||
use openidconnect::IntrospectionUrl;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zitadel::{
|
||||
axum::introspection::IntrospectionStateBuilderError,
|
||||
credentials::Application,
|
||||
@ -15,10 +16,17 @@ use zitadel::{
|
||||
|
||||
use crate::login::AuthClap;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct IdToken {
|
||||
pub sub: String,
|
||||
pub email: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Introspection {
|
||||
async fn get_user(&self) -> anyhow::Result<()>;
|
||||
async fn get_id_token(&self, token: &str) -> anyhow::Result<String>;
|
||||
async fn get_id_token(&self, token: &str) -> anyhow::Result<IdToken>;
|
||||
}
|
||||
|
||||
pub struct IntrospectionService(Arc<dyn Introspection + Send + Sync + 'static>);
|
||||
@ -61,7 +69,7 @@ impl Introspection for ZitadelIntrospection {
|
||||
async fn get_user(&self) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
async fn get_id_token(&self, token: &str) -> anyhow::Result<String> {
|
||||
async fn get_id_token(&self, token: &str) -> anyhow::Result<IdToken> {
|
||||
let config = &self.state.config;
|
||||
let res = introspect(
|
||||
&config.introspection_uri,
|
||||
@ -71,10 +79,21 @@ impl Introspection for ZitadelIntrospection {
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(res
|
||||
let sub = res
|
||||
.sub()
|
||||
.ok_or(anyhow::anyhow!("could not find a userid (sub) in token"))?
|
||||
.to_string())
|
||||
.to_string();
|
||||
|
||||
let extra = res.extra_fields();
|
||||
let email = extra.email.clone().ok_or(anyhow::anyhow!(
|
||||
"could not find a email (scope email) in token"
|
||||
))?;
|
||||
|
||||
let name = extra.name.clone().ok_or(anyhow::anyhow!(
|
||||
"could not find a name (scope profile) in token"
|
||||
))?;
|
||||
|
||||
Ok(IdToken { sub, email, name })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use async_trait::async_trait;
|
||||
use axum_sessions::async_session::{Session as AxumSession, SessionStore as AxumSessionStore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::login::AuthClap;
|
||||
use crate::{introspection::IdToken, login::AuthClap};
|
||||
|
||||
#[derive(clap::Args, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SessionClap {
|
||||
@ -27,8 +27,8 @@ pub struct PostgresqlSessionClap {
|
||||
|
||||
#[async_trait]
|
||||
pub trait Session {
|
||||
async fn insert_user(&self, id: &str, user_id: &str) -> anyhow::Result<String>;
|
||||
async fn get_user(&self, cookie: &str) -> anyhow::Result<Option<String>>;
|
||||
async fn insert_user(&self, id: &str, id_token: IdToken) -> anyhow::Result<String>;
|
||||
async fn get_user(&self, cookie: &str) -> anyhow::Result<Option<User>>;
|
||||
}
|
||||
|
||||
pub struct SessionService(Arc<dyn Session + Send + Sync + 'static>);
|
||||
@ -73,16 +73,20 @@ pub struct PostgresSessionService {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
pub email: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Session for PostgresSessionService {
|
||||
async fn insert_user(&self, _id: &str, user_id: &str) -> anyhow::Result<String> {
|
||||
async fn insert_user(&self, _id: &str, id_token: IdToken) -> anyhow::Result<String> {
|
||||
let mut session = AxumSession::new();
|
||||
session.insert(
|
||||
"user",
|
||||
User {
|
||||
id: user_id.to_string(),
|
||||
id: id_token.sub,
|
||||
email: id_token.email,
|
||||
name: id_token.name,
|
||||
},
|
||||
)?;
|
||||
|
||||
@ -94,14 +98,14 @@ impl Session for PostgresSessionService {
|
||||
|
||||
Ok(cookie)
|
||||
}
|
||||
async fn get_user(&self, cookie: &str) -> anyhow::Result<Option<String>> {
|
||||
async fn get_user(&self, cookie: &str) -> anyhow::Result<Option<User>> {
|
||||
if let Some(session) = self.store.load_session(cookie.to_string()).await.unwrap() {
|
||||
if let Some(user) = session.get::<User>("user") {
|
||||
tracing::debug!(
|
||||
"UserFromSession: session decoded success, user_id={:?}",
|
||||
user.id
|
||||
);
|
||||
Ok(Some(user.id))
|
||||
Ok(Some(user))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@ -119,11 +123,11 @@ pub struct InMemorySessionService {}
|
||||
|
||||
#[async_trait]
|
||||
impl Session for InMemorySessionService {
|
||||
async fn insert_user(&self, _id: &str, _user_id: &str) -> anyhow::Result<String> {
|
||||
async fn insert_user(&self, _id: &str, _id_token: IdToken) -> anyhow::Result<String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn get_user(&self, _cookie: &str) -> anyhow::Result<Option<String>> {
|
||||
async fn get_user(&self, _cookie: &str) -> anyhow::Result<Option<User>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user