You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-11-20 12:02:22 +03:00
Add a dedicated keystore crate
This commit is contained in:
@@ -12,8 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{extract::Extension, response::IntoResponse, Json};
|
||||
use mas_iana::{
|
||||
jose::JsonWebSignatureAlg,
|
||||
@@ -22,7 +20,7 @@ use mas_iana::{
|
||||
PkceCodeChallengeMethod,
|
||||
},
|
||||
};
|
||||
use mas_jose::{SigningKeystore, StaticKeystore};
|
||||
use mas_keystore::Keystore;
|
||||
use mas_router::UrlBuilder;
|
||||
use oauth2_types::{
|
||||
oidc::{ClaimType, ProviderMetadata, SubjectType},
|
||||
@@ -32,7 +30,7 @@ use oauth2_types::{
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(crate) async fn get(
|
||||
Extension(key_store): Extension<Arc<StaticKeystore>>,
|
||||
Extension(key_store): Extension<Keystore>,
|
||||
Extension(url_builder): Extension<UrlBuilder>,
|
||||
) -> impl IntoResponse {
|
||||
// This is how clients can authenticate
|
||||
@@ -54,12 +52,7 @@ pub(crate) async fn get(
|
||||
]);
|
||||
|
||||
// This is how we can sign stuff
|
||||
let jwt_signing_alg_values_supported = Some({
|
||||
let algs = key_store.supported_algorithms();
|
||||
let mut algs = Vec::from_iter(algs);
|
||||
algs.sort();
|
||||
algs
|
||||
});
|
||||
let jwt_signing_alg_values_supported = Some(key_store.available_signing_algorithms());
|
||||
|
||||
// Prepare all the endpoints
|
||||
let issuer = Some(url_builder.oidc_issuer());
|
||||
|
||||
@@ -12,14 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{convert::Infallible, sync::Arc};
|
||||
|
||||
use axum::{extract::Extension, response::IntoResponse, Json};
|
||||
use mas_jose::StaticKeystore;
|
||||
use mas_keystore::Keystore;
|
||||
|
||||
pub(crate) async fn get(
|
||||
Extension(key_store): Extension<Arc<StaticKeystore>>,
|
||||
) -> Result<impl IntoResponse, Infallible> {
|
||||
let jwks = key_store.to_public_jwks();
|
||||
Ok(Json(jwks))
|
||||
pub(crate) async fn get(Extension(key_store): Extension<Keystore>) -> impl IntoResponse {
|
||||
let jwks = key_store.public_jwks();
|
||||
Json(jwks)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Context;
|
||||
use axum::{extract::Extension, response::IntoResponse, Json};
|
||||
@@ -26,8 +26,10 @@ use mas_data_model::{AuthorizationGrantStage, Client, TokenType};
|
||||
use mas_iana::jose::JsonWebSignatureAlg;
|
||||
use mas_jose::{
|
||||
claims::{self, ClaimError},
|
||||
DecodedJsonWebToken, JwtSignatureError, SigningKeystore, StaticKeystore,
|
||||
constraints::Constrainable,
|
||||
jwt::{JsonWebSignatureHeader, Jwt, JwtSignatureError},
|
||||
};
|
||||
use mas_keystore::Keystore;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::{
|
||||
oauth2::{
|
||||
@@ -161,6 +163,12 @@ impl IntoResponse for RouteError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mas_keystore::WrongAlgorithmError> for RouteError {
|
||||
fn from(e: mas_keystore::WrongAlgorithmError) -> Self {
|
||||
Self::Internal(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for RouteError {
|
||||
fn from(e: sqlx::Error) -> Self {
|
||||
Self::Internal(Box::new(e))
|
||||
@@ -182,7 +190,7 @@ impl From<JwtSignatureError> for RouteError {
|
||||
#[tracing::instrument(skip_all, err)]
|
||||
pub(crate) async fn post(
|
||||
client_authorization: ClientAuthorization<AccessTokenRequest>,
|
||||
Extension(key_store): Extension<Arc<StaticKeystore>>,
|
||||
Extension(key_store): Extension<Keystore>,
|
||||
Extension(url_builder): Extension<UrlBuilder>,
|
||||
Extension(pool): Extension<PgPool>,
|
||||
Extension(encrypter): Extension<Encrypter>,
|
||||
@@ -235,7 +243,7 @@ fn hash<H: Digest>(mut hasher: H, token: &str) -> anyhow::Result<String> {
|
||||
async fn authorization_code_grant(
|
||||
grant: &AuthorizationCodeGrant,
|
||||
client: &Client<PostgresqlBackend>,
|
||||
key_store: &StaticKeystore,
|
||||
key_store: &Keystore,
|
||||
url_builder: &UrlBuilder,
|
||||
mut txn: Transaction<'_, Postgres>,
|
||||
) -> Result<AccessTokenResponse, RouteError> {
|
||||
@@ -339,17 +347,19 @@ async fn authorization_code_grant(
|
||||
claims::AT_HASH.insert(&mut claims, hash(Sha256::new(), &access_token_str)?)?;
|
||||
claims::C_HASH.insert(&mut claims, hash(Sha256::new(), &grant.code)?)?;
|
||||
|
||||
let header = key_store
|
||||
.prepare_header(
|
||||
client
|
||||
.id_token_signed_response_alg
|
||||
.unwrap_or(JsonWebSignatureAlg::Rs256),
|
||||
)
|
||||
.await?;
|
||||
let id_token = DecodedJsonWebToken::new(header, claims);
|
||||
let id_token = id_token.sign(key_store).await?;
|
||||
let alg = client
|
||||
.id_token_signed_response_alg
|
||||
.unwrap_or(JsonWebSignatureAlg::Rs256);
|
||||
let key = key_store
|
||||
.signing_key_for_algorithm(alg)
|
||||
.context("no suitable key found")?;
|
||||
|
||||
Some(id_token.serialize())
|
||||
let header = JsonWebSignatureHeader::new(alg)
|
||||
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
||||
let signer = key.params().signer_for_alg(alg)?;
|
||||
let id_token = Jwt::sign(header, claims, &signer)?;
|
||||
|
||||
Some(id_token.as_str().to_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use axum::{
|
||||
extract::Extension,
|
||||
response::{IntoResponse, Response},
|
||||
@@ -21,7 +20,11 @@ use axum::{
|
||||
};
|
||||
use headers::ContentType;
|
||||
use mas_axum_utils::{user_authorization::UserAuthorization, FancyError};
|
||||
use mas_jose::{DecodedJsonWebToken, SigningKeystore, StaticKeystore};
|
||||
use mas_jose::{
|
||||
constraints::Constrainable,
|
||||
jwt::{JsonWebSignatureHeader, Jwt},
|
||||
};
|
||||
use mas_keystore::Keystore;
|
||||
use mas_router::UrlBuilder;
|
||||
use mime::Mime;
|
||||
use oauth2_types::scope;
|
||||
@@ -49,7 +52,7 @@ struct SignedUserInfo {
|
||||
pub async fn get(
|
||||
Extension(url_builder): Extension<UrlBuilder>,
|
||||
Extension(pool): Extension<PgPool>,
|
||||
Extension(key_store): Extension<Arc<StaticKeystore>>,
|
||||
Extension(key_store): Extension<Keystore>,
|
||||
user_authorization: UserAuthorization,
|
||||
) -> Result<Response, FancyError> {
|
||||
// TODO: error handling
|
||||
@@ -73,7 +76,13 @@ pub async fn get(
|
||||
}
|
||||
|
||||
if let Some(alg) = session.client.userinfo_signed_response_alg {
|
||||
let header = key_store.prepare_header(alg).await?;
|
||||
let key = key_store
|
||||
.signing_key_for_algorithm(alg)
|
||||
.context("no suitable key found")?;
|
||||
|
||||
let header = JsonWebSignatureHeader::new(alg)
|
||||
.with_kid(key.kid().context("key has no `kid` for some reason")?);
|
||||
let signer = key.params().signer_for_alg(alg)?;
|
||||
|
||||
let user_info = SignedUserInfo {
|
||||
iss: url_builder.oidc_issuer().to_string(),
|
||||
@@ -81,13 +90,10 @@ pub async fn get(
|
||||
user_info,
|
||||
};
|
||||
|
||||
let user_info = DecodedJsonWebToken::new(header, user_info);
|
||||
let user_info = user_info.sign(key_store.as_ref()).await?;
|
||||
|
||||
let token = user_info.serialize();
|
||||
let token = Jwt::sign(header, user_info, &signer)?;
|
||||
let application_jwt: Mime = "application/jwt".parse().unwrap();
|
||||
let content_type = ContentType::from(application_jwt);
|
||||
Ok((TypedHeader(content_type), token).into_response())
|
||||
Ok((TypedHeader(content_type), token.as_str().to_owned()).into_response())
|
||||
} else {
|
||||
Ok(Json(user_info).into_response())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user