ezidam: added openid configration, well known route
This commit is contained in:
parent
44506422e9
commit
2d0d6857ce
10 changed files with 647 additions and 2 deletions
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.5.0-rc.2"
|
||||
rocket = { version = "0.5.0-rc.2", features = ["json"] }
|
||||
rocket_db_pools = { version = "0.1.0-rc.2", features = ["sqlx_sqlite"] }
|
||||
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
|
||||
infer = { version = "0.12.0", default-features = false }
|
||||
|
|
@ -18,3 +18,5 @@ settings = { path = "../settings" }
|
|||
users = { path = "../users" }
|
||||
id = { path = "../id" }
|
||||
hash = { path = "../hash" }
|
||||
openid = { path = "../openid" }
|
||||
jwt = { path = "../jwt" }
|
||||
|
|
|
|||
|
|
@ -29,3 +29,9 @@ impl From<users::Error> for Error {
|
|||
Error::internal_server_error(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<openid::Error> for Error {
|
||||
fn from(e: openid::Error) -> Self {
|
||||
Error::internal_server_error(e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use rocket::{Build, Rocket};
|
|||
pub mod auth;
|
||||
pub mod root;
|
||||
pub mod setup;
|
||||
pub mod well_known;
|
||||
|
||||
pub(self) mod prelude {
|
||||
pub use crate::database::Database;
|
||||
|
|
@ -34,4 +35,5 @@ pub fn routes(rocket_builder: Rocket<Build>) -> Rocket<Build> {
|
|||
// Setup
|
||||
.mount("/setup", setup::routes())
|
||||
.mount("/auth", auth::routes())
|
||||
.mount("/.well-known", well_known::routes())
|
||||
}
|
||||
|
|
|
|||
25
crates/ezidam/src/routes/well_known.rs
Normal file
25
crates/ezidam/src/routes/well_known.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use super::prelude::*;
|
||||
use rocket::get;
|
||||
use rocket::serde::json::{Json, Value};
|
||||
use settings::Settings;
|
||||
|
||||
pub fn routes() -> Vec<Route> {
|
||||
routes![openid_configuration]
|
||||
}
|
||||
|
||||
#[get("/openid-configuration")]
|
||||
async fn openid_configuration(mut db: Connection<Database>) -> Result<Json<Value>> {
|
||||
// Get settings
|
||||
let settings = Settings::get(&mut *db).await?;
|
||||
|
||||
// Get server url
|
||||
let url = settings
|
||||
.url()
|
||||
.ok_or_else(|| Error::not_found("Server url"))?;
|
||||
|
||||
// Create openid configuration
|
||||
let openid_configuration = openid::configuration(url)?;
|
||||
|
||||
// HTTP response
|
||||
Ok(Json(openid_configuration))
|
||||
}
|
||||
10
crates/openid/Cargo.toml
Normal file
10
crates/openid/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "openid"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
openidconnect = { version = "3.0.0-alpha.1", default-features = false }
|
||||
11
crates/openid/src/error.rs
Normal file
11
crates/openid/src/error.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// error
|
||||
#[derive(thiserror::Error)]
|
||||
// the rest
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
#[error("Failed to parse an URL: `{0}`")]
|
||||
UrlParse(#[from] url::ParseError),
|
||||
|
||||
#[error("Failed to serialize to JSON: `{0}`")]
|
||||
JsonSerialization(#[from] serde_json::Error),
|
||||
}
|
||||
6
crates/openid/src/lib.rs
Normal file
6
crates/openid/src/lib.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
mod error;
|
||||
mod openid;
|
||||
|
||||
/// Exports
|
||||
pub use error::Error;
|
||||
pub use openid::configuration;
|
||||
66
crates/openid/src/openid.rs
Normal file
66
crates/openid/src/openid.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
use crate::error::Error;
|
||||
use openidconnect::core::{
|
||||
CoreClaimName, CoreJwsSigningAlgorithm, CoreProviderMetadata, CoreResponseType,
|
||||
CoreSubjectIdentifierType,
|
||||
};
|
||||
use openidconnect::{
|
||||
AuthUrl, EmptyAdditionalProviderMetadata, IssuerUrl, JsonWebKeySetUrl, ResponseTypes, Scope,
|
||||
TokenUrl, UserInfoUrl,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
pub fn configuration(base_url: &str) -> Result<Value, Error> {
|
||||
let base_url = Url::parse(base_url)?;
|
||||
|
||||
let authorization_endpoint = base_url.join("/oauth/authorize")?;
|
||||
let jwks_uri = base_url.join("/.well-known/jwks.json")?;
|
||||
let token_url = base_url.join("/oauth/token")?;
|
||||
let user_info_url = base_url.join("/oauth/userinfo")?;
|
||||
|
||||
let provider_metadata = CoreProviderMetadata::new(
|
||||
// Parameters required by the OpenID Connect Discovery spec.
|
||||
IssuerUrl::from_url(base_url),
|
||||
AuthUrl::from_url(authorization_endpoint),
|
||||
// Use the JsonWebKeySet struct to serve the JWK Set at this URL.
|
||||
JsonWebKeySetUrl::from_url(jwks_uri),
|
||||
// Supported response types (flows).
|
||||
vec![
|
||||
// Recommended: support the code flow.
|
||||
ResponseTypes::new(vec![CoreResponseType::Code]),
|
||||
// Optional: support the implicit flow.
|
||||
ResponseTypes::new(vec![CoreResponseType::Token, CoreResponseType::IdToken]), // Other flows including hybrid flows may also be specified here.
|
||||
],
|
||||
// For user privacy, the Pairwise subject identifier type is preferred. This prevents
|
||||
// distinct relying parties (clients) from knowing whether their users represent the same
|
||||
// real identities. This identifier type is only useful for relying parties that don't
|
||||
// receive the 'email', 'profile' or other personally-identifying scopes.
|
||||
// The Public subject identifier type is also supported.
|
||||
vec![CoreSubjectIdentifierType::Pairwise],
|
||||
vec![CoreJwsSigningAlgorithm::RsaSsaPssSha256],
|
||||
// OpenID Connect Providers may supply custom metadata by providing a struct that
|
||||
// implements the AdditionalProviderMetadata trait. This requires manually using the
|
||||
// generic ProviderMetadata struct rather than the CoreProviderMetadata type alias,
|
||||
// however.
|
||||
EmptyAdditionalProviderMetadata {},
|
||||
)
|
||||
// Specify the token endpoint (required for the code flow).
|
||||
.set_token_endpoint(Some(TokenUrl::from_url(token_url)))
|
||||
// Recommended: support the UserInfo endpoint.
|
||||
.set_userinfo_endpoint(Some(UserInfoUrl::from_url(user_info_url)))
|
||||
// Recommended: specify the supported scopes.
|
||||
.set_scopes_supported(Some(vec![Scope::new("openid".to_string())]))
|
||||
// Recommended: specify the supported ID token claims.
|
||||
.set_claims_supported(Some(vec![
|
||||
// Providers may also define an enum instead of using CoreClaimName.
|
||||
CoreClaimName::new("sub".to_string()),
|
||||
CoreClaimName::new("aud".to_string()),
|
||||
CoreClaimName::new("email".to_string()),
|
||||
CoreClaimName::new("exp".to_string()),
|
||||
CoreClaimName::new("iat".to_string()),
|
||||
CoreClaimName::new("iss".to_string()),
|
||||
CoreClaimName::new("name".to_string()),
|
||||
]));
|
||||
|
||||
Ok(serde_json::to_value(provider_metadata)?)
|
||||
}
|
||||
|
|
@ -23,4 +23,7 @@ impl Settings {
|
|||
pub fn business_name(&self) -> &str {
|
||||
&self.business_name
|
||||
}
|
||||
pub fn url(&self) -> Option<&str> {
|
||||
self.url.as_deref()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue