1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

Support private_key_jwt client auth

Which includes having a verifying keystore out of JWKS (and soon out of
a JWKS URI)
This commit is contained in:
Quentin Gliech
2022-01-05 21:07:18 +01:00
parent f7706f2351
commit a965e488e2
14 changed files with 557 additions and 129 deletions

View File

@@ -38,7 +38,7 @@ pub use self::{
csrf::CsrfConfig,
database::DatabaseConfig,
http::HttpConfig,
oauth2::{OAuth2ClientConfig, OAuth2Config},
oauth2::{OAuth2ClientAuthMethodConfig, OAuth2ClientConfig, OAuth2Config},
telemetry::{
MetricsConfig, MetricsExporterConfig, Propagator, TelemetryConfig, TracingConfig,
TracingExporterConfig,

View File

@@ -14,7 +14,7 @@
use anyhow::Context;
use async_trait::async_trait;
use mas_jose::StaticKeystore;
use mas_jose::{JsonWebKeySet, StaticJwksStore, StaticKeystore};
use pkcs8::{DecodePrivateKey, EncodePrivateKey};
use rsa::{
pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey},
@@ -43,13 +43,41 @@ pub struct KeyConfig {
key: String,
}
#[derive(JsonSchema, Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum JwksOrJwksUri {
Jwks(JsonWebKeySet),
JwksUri(Url),
}
impl JwksOrJwksUri {
pub fn key_store(&self) -> StaticJwksStore {
let jwks = match self {
Self::Jwks(jwks) => jwks.clone(),
Self::JwksUri(_) => unimplemented!("jwks_uri are not implemented yet"),
};
StaticJwksStore::new(jwks)
}
}
#[derive(JsonSchema, Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "client_auth_method", rename_all = "snake_case")]
pub enum OAuth2ClientAuthMethodConfig {
None,
ClientSecretBasic { client_secret: String },
ClientSecretPost { client_secret: String },
ClientSecretJwt { client_secret: String },
PrivateKeyJwt(JwksOrJwksUri),
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct OAuth2ClientConfig {
pub client_id: String,
#[serde(default)]
pub client_secret: Option<String>,
#[serde(flatten)]
pub client_auth_method: OAuth2ClientAuthMethodConfig,
#[serde(default)]
pub redirect_uris: Vec<Url>,
@@ -246,25 +274,55 @@ mod tests {
-----END PRIVATE KEY-----
issuer: https://example.com
clients:
- client_id: hello
- client_id: public
client_auth_method: none
redirect_uris:
- https://exemple.fr/callback
- client_id: world
- client_id: secret-basic
client_auth_method: client_secret_basic
client_secret: hello
- client_id: secret-post
client_auth_method: client_secret_post
client_secret: hello
- client_id: secret-jwk
client_auth_method: client_secret_jwt
client_secret: hello
- client_id: jwks
client_auth_method: private_key_jwt
jwks:
keys:
- kid: "03e84aed4ef4431014e8617567864c4efaaaede9"
kty: "RSA"
alg: "RS256"
use: "sig"
e: "AQAB"
n: "ma2uRyBeSEOatGuDpCiV9oIxlDWix_KypDYuhQfEzqi_BiF4fV266OWfyjcABbam59aJMNvOnKW3u_eZM-PhMCBij5MZ-vcBJ4GfxDJeKSn-GP_dJ09rpDcILh8HaWAnPmMoi4DC0nrfE241wPISvZaaZnGHkOrfN_EnA5DligLgVUbrA5rJhQ1aSEQO_gf1raEOW3DZ_ACU3qhtgO0ZBG3a5h7BPiRs2sXqb2UCmBBgwyvYLDebnpE7AotF6_xBIlR-Cykdap3GHVMXhrIpvU195HF30ZoBU4dMd-AeG6HgRt4Cqy1moGoDgMQfbmQ48Hlunv9_Vi2e2CLvYECcBw"
- kid: "d01c1abe249269f72ef7ca2613a86c9f05e59567"
kty: "RSA"
alg: "RS256"
use: "sig"
e: "AQAB"
n: "0hukqytPwrj1RbMYhYoepCi3CN5k7DwYkTe_Cmb7cP9_qv4ok78KdvFXt5AnQxCRwBD7-qTNkkfMWO2RxUMBdQD0ED6tsSb1n5dp0XY8dSWiBDCX8f6Hr-KolOpvMLZKRy01HdAWcM6RoL9ikbjYHUEW1C8IJnw3MzVHkpKFDL354aptdNLaAdTCBvKzU9WpXo10g-5ctzSlWWjQuecLMQ4G1mNdsR1LHhUENEnOvgT8cDkX0fJzLbEbyBYkdMgKggyVPEB1bg6evG4fTKawgnf0IDSPxIU-wdS9wdSP9ZCJJPLi5CEp-6t6rE_sb2dGcnzjCGlembC57VwpkUvyMw"
"#,
)?;
let config = OAuth2Config::load_from_file("config.yaml")?;
assert_eq!(config.issuer, "https://example.com".parse().unwrap());
assert_eq!(config.clients.len(), 2);
assert_eq!(config.clients.len(), 5);
assert_eq!(config.clients[0].client_id, "hello");
assert_eq!(config.clients[0].client_id, "public");
assert_eq!(
config.clients[0].redirect_uris,
vec!["https://exemple.fr/callback".parse().unwrap()]
);
assert_eq!(config.clients[1].client_id, "world");
assert_eq!(config.clients[1].client_id, "secret-basic");
assert_eq!(config.clients[1].redirect_uris, Vec::new());
Ok(())