You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Save the application_type and the contacts in the OAuth 2.0 clients
This also removes the dedicated "redirect_uris" table and makes it a field of the "oauth2_clients" table
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
default-members = ["crates/cli"]
|
default-members = ["crates/cli"]
|
||||||
members = ["crates/*"]
|
members = ["crates/*"]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
||||||
|
@ -140,7 +140,6 @@ impl Options {
|
|||||||
#[tracing::instrument(name = "cli.config.sync", skip(root), err(Debug))]
|
#[tracing::instrument(name = "cli.config.sync", skip(root), err(Debug))]
|
||||||
async fn sync(root: &super::Options, prune: bool, dry_run: bool) -> anyhow::Result<()> {
|
async fn sync(root: &super::Options, prune: bool, dry_run: bool) -> anyhow::Result<()> {
|
||||||
// XXX: we should disallow SeedableRng::from_entropy
|
// XXX: we should disallow SeedableRng::from_entropy
|
||||||
let mut rng = rand_chacha::ChaChaRng::from_entropy();
|
|
||||||
let clock = SystemClock::default();
|
let clock = SystemClock::default();
|
||||||
|
|
||||||
let config: SyncConfig = root.load_config()?;
|
let config: SyncConfig = root.load_config()?;
|
||||||
@ -282,8 +281,6 @@ async fn sync(root: &super::Options, prune: bool, dry_run: bool) -> anyhow::Resu
|
|||||||
|
|
||||||
repo.oauth2_client()
|
repo.oauth2_client()
|
||||||
.upsert_static(
|
.upsert_static(
|
||||||
&mut rng,
|
|
||||||
&clock,
|
|
||||||
client.client_id,
|
client.client_id,
|
||||||
client_auth_method,
|
client_auth_method,
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
@ -18,7 +18,7 @@ use mas_iana::{
|
|||||||
oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
|
oauth::{OAuthAuthorizationEndpointResponseType, OAuthClientAuthenticationMethod},
|
||||||
};
|
};
|
||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
use oauth2_types::requests::GrantType;
|
use oauth2_types::{oidc::ApplicationType, requests::GrantType};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -44,6 +44,8 @@ pub struct Client {
|
|||||||
|
|
||||||
pub encrypted_client_secret: Option<String>,
|
pub encrypted_client_secret: Option<String>,
|
||||||
|
|
||||||
|
pub application_type: Option<ApplicationType>,
|
||||||
|
|
||||||
/// Array of Redirection URI values used by the Client
|
/// Array of Redirection URI values used by the Client
|
||||||
pub redirect_uris: Vec<Url>,
|
pub redirect_uris: Vec<Url>,
|
||||||
|
|
||||||
@ -130,6 +132,7 @@ impl Client {
|
|||||||
id: Ulid::from_datetime_with_source(now.into(), rng),
|
id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
client_id: "client1".to_owned(),
|
client_id: "client1".to_owned(),
|
||||||
encrypted_client_secret: None,
|
encrypted_client_secret: None,
|
||||||
|
application_type: Some(ApplicationType::Web),
|
||||||
redirect_uris: vec![
|
redirect_uris: vec![
|
||||||
Url::parse("https://client1.example.com/redirect").unwrap(),
|
Url::parse("https://client1.example.com/redirect").unwrap(),
|
||||||
Url::parse("https://client1.example.com/redirect2").unwrap(),
|
Url::parse("https://client1.example.com/redirect2").unwrap(),
|
||||||
@ -156,6 +159,7 @@ impl Client {
|
|||||||
id: Ulid::from_datetime_with_source(now.into(), rng),
|
id: Ulid::from_datetime_with_source(now.into(), rng),
|
||||||
client_id: "client2".to_owned(),
|
client_id: "client2".to_owned(),
|
||||||
encrypted_client_secret: None,
|
encrypted_client_secret: None,
|
||||||
|
application_type: Some(ApplicationType::Native),
|
||||||
redirect_uris: vec![Url::parse("https://client2.example.com/redirect").unwrap()],
|
redirect_uris: vec![Url::parse("https://client2.example.com/redirect").unwrap()],
|
||||||
response_types: vec![OAuthAuthorizationEndpointResponseType::Code],
|
response_types: vec![OAuthAuthorizationEndpointResponseType::Code],
|
||||||
grant_types: vec![GrantType::AuthorizationCode, GrantType::RefreshToken],
|
grant_types: vec![GrantType::AuthorizationCode, GrantType::RefreshToken],
|
||||||
|
@ -17,7 +17,7 @@ use async_graphql::{Context, Description, Enum, Object, ID};
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::SessionState;
|
use mas_data_model::SessionState;
|
||||||
use mas_storage::{oauth2::OAuth2ClientRepository, user::BrowserSessionRepository};
|
use mas_storage::{oauth2::OAuth2ClientRepository, user::BrowserSessionRepository};
|
||||||
use oauth2_types::scope::Scope;
|
use oauth2_types::{oidc::ApplicationType, scope::Scope};
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -110,6 +110,16 @@ impl OAuth2Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The application type advertised by the client.
|
||||||
|
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum OAuth2ApplicationType {
|
||||||
|
/// Client is a web application.
|
||||||
|
Web,
|
||||||
|
|
||||||
|
/// Client is a native application.
|
||||||
|
Native,
|
||||||
|
}
|
||||||
|
|
||||||
/// An OAuth 2.0 client
|
/// An OAuth 2.0 client
|
||||||
#[derive(Description)]
|
#[derive(Description)]
|
||||||
pub struct OAuth2Client(pub mas_data_model::Client);
|
pub struct OAuth2Client(pub mas_data_model::Client);
|
||||||
@ -150,6 +160,19 @@ impl OAuth2Client {
|
|||||||
pub async fn redirect_uris(&self) -> &[Url] {
|
pub async fn redirect_uris(&self) -> &[Url] {
|
||||||
&self.0.redirect_uris
|
&self.0.redirect_uris
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List of contacts advertised by the client.
|
||||||
|
pub async fn contacts(&self) -> &[String] {
|
||||||
|
&self.0.contacts
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The application type advertised by the client.
|
||||||
|
pub async fn application_type(&self) -> Option<OAuth2ApplicationType> {
|
||||||
|
match self.0.application_type? {
|
||||||
|
ApplicationType::Web => Some(OAuth2ApplicationType::Web),
|
||||||
|
ApplicationType::Native => Some(OAuth2ApplicationType::Native),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An OAuth 2.0 consent represents the scope a user consented to grant to a
|
/// An OAuth 2.0 consent represents the scope a user consented to grant to a
|
||||||
|
@ -33,6 +33,7 @@ async fn create_test_client(state: &TestState) -> Client {
|
|||||||
&state.clock,
|
&state.clock,
|
||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
vec![],
|
vec![],
|
||||||
vec![],
|
vec![],
|
||||||
None,
|
None,
|
||||||
|
@ -175,6 +175,7 @@ pub(crate) async fn post(
|
|||||||
&clock,
|
&clock,
|
||||||
metadata.redirect_uris().to_vec(),
|
metadata.redirect_uris().to_vec(),
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
metadata.application_type,
|
||||||
//&metadata.response_types(),
|
//&metadata.response_types(),
|
||||||
metadata.grant_types().to_vec(),
|
metadata.grant_types().to_vec(),
|
||||||
metadata.contacts.clone().unwrap_or_default(),
|
metadata.contacts.clone().unwrap_or_default(),
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, FALSE)\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Text",
|
|
||||||
"Bool",
|
|
||||||
"Bool",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Jsonb",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "31cbbd841029812c6d3500cae04a8e9e5723e4749d339465492b68e072c3a802"
|
|
||||||
}
|
|
31
crates/storage-pg/.sqlx/query-34fbe0f0485a9c4060399509f087964c454252b9b111a57c9106cfc3fdc71b8a.json
generated
Normal file
31
crates/storage-pg/.sqlx/query-34fbe0f0485a9c4060399509f087964c454252b9b111a57c9106cfc3fdc71b8a.json
generated
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, FALSE)\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"TextArray",
|
||||||
|
"Bool",
|
||||||
|
"Bool",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Jsonb",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text",
|
||||||
|
"Text"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "34fbe0f0485a9c4060399509f087964c454252b9b111a57c9106cfc3fdc71b8a"
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , ARRAY(\n SELECT redirect_uri\n FROM oauth2_client_redirect_uris r\n WHERE r.oauth2_client_id = c.oauth2_client_id\n ) AS \"redirect_uris!\"\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = ANY($1::uuid[])\n ",
|
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = ANY($1::uuid[])\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -15,76 +15,86 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"name": "redirect_uris!",
|
"name": "application_type",
|
||||||
"type_info": "TextArray"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
|
"name": "redirect_uris",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
"name": "grant_type_authorization_code",
|
"name": "grant_type_authorization_code",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 4,
|
"ordinal": 5,
|
||||||
"name": "grant_type_refresh_token",
|
"name": "grant_type_refresh_token",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 5,
|
"ordinal": 6,
|
||||||
|
"name": "contacts",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 7,
|
||||||
"name": "client_name",
|
"name": "client_name",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 6,
|
"ordinal": 8,
|
||||||
"name": "logo_uri",
|
"name": "logo_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 7,
|
"ordinal": 9,
|
||||||
"name": "client_uri",
|
"name": "client_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 8,
|
"ordinal": 10,
|
||||||
"name": "policy_uri",
|
"name": "policy_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 9,
|
"ordinal": 11,
|
||||||
"name": "tos_uri",
|
"name": "tos_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 10,
|
"ordinal": 12,
|
||||||
"name": "jwks_uri",
|
"name": "jwks_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 11,
|
"ordinal": 13,
|
||||||
"name": "jwks",
|
"name": "jwks",
|
||||||
"type_info": "Jsonb"
|
"type_info": "Jsonb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 12,
|
"ordinal": 14,
|
||||||
"name": "id_token_signed_response_alg",
|
"name": "id_token_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 13,
|
"ordinal": 15,
|
||||||
"name": "userinfo_signed_response_alg",
|
"name": "userinfo_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 14,
|
"ordinal": 16,
|
||||||
"name": "token_endpoint_auth_method",
|
"name": "token_endpoint_auth_method",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 15,
|
"ordinal": 17,
|
||||||
"name": "token_endpoint_auth_signing_alg",
|
"name": "token_endpoint_auth_signing_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 16,
|
"ordinal": 18,
|
||||||
"name": "initiate_login_uri",
|
"name": "initiate_login_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -97,7 +107,9 @@
|
|||||||
"nullable": [
|
"nullable": [
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
null,
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
@ -114,5 +126,5 @@
|
|||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "85499663f1adc7b7439592063f06914089f6243126a177b365bde37db5f6b33d"
|
"hash": "35734c4b54d2f1b2c311806af3e9a592f5f55f4898c6e39eb0d7c1b9cef7ca63"
|
||||||
}
|
}
|
@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , grant_type_authorization_code\n , grant_type_refresh_token\n , token_endpoint_auth_method\n , jwks\n , jwks_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, TRUE)\n ON CONFLICT (oauth2_client_id)\n DO\n UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret\n , grant_type_authorization_code = EXCLUDED.grant_type_authorization_code\n , grant_type_refresh_token = EXCLUDED.grant_type_refresh_token\n , token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method\n , jwks = EXCLUDED.jwks\n , jwks_uri = EXCLUDED.jwks_uri\n , is_static = TRUE\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid",
|
|
||||||
"Text",
|
|
||||||
"Bool",
|
|
||||||
"Bool",
|
|
||||||
"Text",
|
|
||||||
"Jsonb",
|
|
||||||
"Text"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "68c4cd463e4035ba8384f11818b7be602e2fbc34a5582f31f95b0cc5fa2aeb92"
|
|
||||||
}
|
|
21
crates/storage-pg/.sqlx/query-73ea17a71d62bf96f7811b7f57802f5065f0ae831bc8f3c66b5be4a47b37467e.json
generated
Normal file
21
crates/storage-pg/.sqlx/query-73ea17a71d62bf96f7811b7f57802f5065f0ae831bc8f3c66b5be4a47b37467e.json
generated
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n INSERT INTO oauth2_clients\n ( oauth2_client_id\n , encrypted_client_secret\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , token_endpoint_auth_method\n , jwks\n , jwks_uri\n , is_static\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, TRUE)\n ON CONFLICT (oauth2_client_id)\n DO\n UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret\n , grant_type_authorization_code = EXCLUDED.grant_type_authorization_code\n , grant_type_refresh_token = EXCLUDED.grant_type_refresh_token\n , token_endpoint_auth_method = EXCLUDED.token_endpoint_auth_method\n , jwks = EXCLUDED.jwks\n , jwks_uri = EXCLUDED.jwks_uri\n , is_static = TRUE\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Uuid",
|
||||||
|
"Text",
|
||||||
|
"TextArray",
|
||||||
|
"Bool",
|
||||||
|
"Bool",
|
||||||
|
"Text",
|
||||||
|
"Jsonb",
|
||||||
|
"Text"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "73ea17a71d62bf96f7811b7f57802f5065f0ae831bc8f3c66b5be4a47b37467e"
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n INSERT INTO oauth2_client_redirect_uris\n (oauth2_client_redirect_uri_id, oauth2_client_id, redirect_uri)\n SELECT id, $2, redirect_uri\n FROM UNNEST($1::uuid[], $3::text[]) r(id, redirect_uri)\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"UuidArray",
|
|
||||||
"Uuid",
|
|
||||||
"TextArray"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "7be139553610ace03193a99fe27fcb4e3d50c90accdaf22ca1cfeefdc9734300"
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"db_name": "PostgreSQL",
|
|
||||||
"query": "\n DELETE FROM oauth2_client_redirect_uris\n WHERE oauth2_client_id = $1\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Uuid"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "7cd0264707100f5b3cb2582f3f840bf66649742374e3643f1902ae69377fc9b6"
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , ARRAY(\n SELECT redirect_uri\n FROM oauth2_client_redirect_uris r\n WHERE r.oauth2_client_id = c.oauth2_client_id\n ) AS \"redirect_uris!\"\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n WHERE is_static = TRUE\n ",
|
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n WHERE is_static = TRUE\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -15,76 +15,86 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"name": "redirect_uris!",
|
"name": "application_type",
|
||||||
"type_info": "TextArray"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
|
"name": "redirect_uris",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
"name": "grant_type_authorization_code",
|
"name": "grant_type_authorization_code",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 4,
|
"ordinal": 5,
|
||||||
"name": "grant_type_refresh_token",
|
"name": "grant_type_refresh_token",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 5,
|
"ordinal": 6,
|
||||||
|
"name": "contacts",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 7,
|
||||||
"name": "client_name",
|
"name": "client_name",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 6,
|
"ordinal": 8,
|
||||||
"name": "logo_uri",
|
"name": "logo_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 7,
|
"ordinal": 9,
|
||||||
"name": "client_uri",
|
"name": "client_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 8,
|
"ordinal": 10,
|
||||||
"name": "policy_uri",
|
"name": "policy_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 9,
|
"ordinal": 11,
|
||||||
"name": "tos_uri",
|
"name": "tos_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 10,
|
"ordinal": 12,
|
||||||
"name": "jwks_uri",
|
"name": "jwks_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 11,
|
"ordinal": 13,
|
||||||
"name": "jwks",
|
"name": "jwks",
|
||||||
"type_info": "Jsonb"
|
"type_info": "Jsonb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 12,
|
"ordinal": 14,
|
||||||
"name": "id_token_signed_response_alg",
|
"name": "id_token_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 13,
|
"ordinal": 15,
|
||||||
"name": "userinfo_signed_response_alg",
|
"name": "userinfo_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 14,
|
"ordinal": 16,
|
||||||
"name": "token_endpoint_auth_method",
|
"name": "token_endpoint_auth_method",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 15,
|
"ordinal": 17,
|
||||||
"name": "token_endpoint_auth_signing_alg",
|
"name": "token_endpoint_auth_signing_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 16,
|
"ordinal": 18,
|
||||||
"name": "initiate_login_uri",
|
"name": "initiate_login_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -95,7 +105,9 @@
|
|||||||
"nullable": [
|
"nullable": [
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
null,
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
@ -112,5 +124,5 @@
|
|||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "7e676491b077d4bc8a9cdb4a27ebf119d98cd35ebb52b1064fdb2d9eed78d0e8"
|
"hash": "b2b71d12c3a4a7436bbe961c6c57e17a5c5e4105d01184a38d12607d853df802"
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , ARRAY(\n SELECT redirect_uri\n FROM oauth2_client_redirect_uris r\n WHERE r.oauth2_client_id = c.oauth2_client_id\n ) AS \"redirect_uris!\"\n , grant_type_authorization_code\n , grant_type_refresh_token\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = $1\n ",
|
"query": "\n SELECT oauth2_client_id\n , encrypted_client_secret\n , application_type\n , redirect_uris\n , grant_type_authorization_code\n , grant_type_refresh_token\n , contacts\n , client_name\n , logo_uri\n , client_uri\n , policy_uri\n , tos_uri\n , jwks_uri\n , jwks\n , id_token_signed_response_alg\n , userinfo_signed_response_alg\n , token_endpoint_auth_method\n , token_endpoint_auth_signing_alg\n , initiate_login_uri\n FROM oauth2_clients c\n\n WHERE oauth2_client_id = $1\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -15,76 +15,86 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 2,
|
"ordinal": 2,
|
||||||
"name": "redirect_uris!",
|
"name": "application_type",
|
||||||
"type_info": "TextArray"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
|
"name": "redirect_uris",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
"name": "grant_type_authorization_code",
|
"name": "grant_type_authorization_code",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 4,
|
"ordinal": 5,
|
||||||
"name": "grant_type_refresh_token",
|
"name": "grant_type_refresh_token",
|
||||||
"type_info": "Bool"
|
"type_info": "Bool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 5,
|
"ordinal": 6,
|
||||||
|
"name": "contacts",
|
||||||
|
"type_info": "TextArray"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 7,
|
||||||
"name": "client_name",
|
"name": "client_name",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 6,
|
"ordinal": 8,
|
||||||
"name": "logo_uri",
|
"name": "logo_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 7,
|
"ordinal": 9,
|
||||||
"name": "client_uri",
|
"name": "client_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 8,
|
"ordinal": 10,
|
||||||
"name": "policy_uri",
|
"name": "policy_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 9,
|
"ordinal": 11,
|
||||||
"name": "tos_uri",
|
"name": "tos_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 10,
|
"ordinal": 12,
|
||||||
"name": "jwks_uri",
|
"name": "jwks_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 11,
|
"ordinal": 13,
|
||||||
"name": "jwks",
|
"name": "jwks",
|
||||||
"type_info": "Jsonb"
|
"type_info": "Jsonb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 12,
|
"ordinal": 14,
|
||||||
"name": "id_token_signed_response_alg",
|
"name": "id_token_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 13,
|
"ordinal": 15,
|
||||||
"name": "userinfo_signed_response_alg",
|
"name": "userinfo_signed_response_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 14,
|
"ordinal": 16,
|
||||||
"name": "token_endpoint_auth_method",
|
"name": "token_endpoint_auth_method",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 15,
|
"ordinal": 17,
|
||||||
"name": "token_endpoint_auth_signing_alg",
|
"name": "token_endpoint_auth_signing_alg",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 16,
|
"ordinal": 18,
|
||||||
"name": "initiate_login_uri",
|
"name": "initiate_login_uri",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
}
|
}
|
||||||
@ -97,7 +107,9 @@
|
|||||||
"nullable": [
|
"nullable": [
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
null,
|
true,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
@ -114,5 +126,5 @@
|
|||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "db90cbc406a399f5447bd2c1d8018464f83b927dec620353516c0285b76fcf24"
|
"hash": "e6250ea5c861cd7568999fd8f490daf1407b1b3619e3a05c70b5fe9ccf9aa7b5"
|
||||||
}
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
-- Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||||
|
--
|
||||||
|
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
-- you may not use this file except in compliance with the License.
|
||||||
|
-- You may obtain a copy of the License at
|
||||||
|
--
|
||||||
|
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
--
|
||||||
|
-- Unless required by applicable law or agreed to in writing, software
|
||||||
|
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
-- See the License for the specific language governing permissions and
|
||||||
|
-- limitations under the License.
|
||||||
|
|
||||||
|
-- Adds a few fields to OAuth 2.0 clients, and squash the redirect_uris in the same table
|
||||||
|
|
||||||
|
ALTER TABLE "oauth2_clients"
|
||||||
|
ADD COLUMN "redirect_uris" TEXT[] NOT NULL DEFAULT '{}',
|
||||||
|
ADD COLUMN "application_type" TEXT,
|
||||||
|
ADD COLUMN "contacts" TEXT[] NOT NULL DEFAULT '{}';
|
||||||
|
|
||||||
|
-- Insert in the new `redirect_uris` column the values from the old table
|
||||||
|
UPDATE "oauth2_clients"
|
||||||
|
SET "redirect_uris" = ARRAY(
|
||||||
|
SELECT "redirect_uri"
|
||||||
|
FROM "oauth2_client_redirect_uris"
|
||||||
|
WHERE "oauth2_client_redirect_uris"."oauth2_client_id" = "oauth2_clients"."oauth2_client_id"
|
||||||
|
GROUP BY "redirect_uri"
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Drop the old table
|
||||||
|
DROP TABLE "oauth2_client_redirect_uris";
|
@ -27,6 +27,7 @@ use mas_iana::{
|
|||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
use mas_storage::{oauth2::OAuth2ClientRepository, Clock};
|
use mas_storage::{oauth2::OAuth2ClientRepository, Clock};
|
||||||
use oauth2_types::{
|
use oauth2_types::{
|
||||||
|
oidc::ApplicationType,
|
||||||
requests::GrantType,
|
requests::GrantType,
|
||||||
scope::{Scope, ScopeToken},
|
scope::{Scope, ScopeToken},
|
||||||
};
|
};
|
||||||
@ -57,11 +58,12 @@ impl<'c> PgOAuth2ClientRepository<'c> {
|
|||||||
struct OAuth2ClientLookup {
|
struct OAuth2ClientLookup {
|
||||||
oauth2_client_id: Uuid,
|
oauth2_client_id: Uuid,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
|
application_type: Option<String>,
|
||||||
redirect_uris: Vec<String>,
|
redirect_uris: Vec<String>,
|
||||||
// response_types: Vec<String>,
|
// response_types: Vec<String>,
|
||||||
grant_type_authorization_code: bool,
|
grant_type_authorization_code: bool,
|
||||||
grant_type_refresh_token: bool,
|
grant_type_refresh_token: bool,
|
||||||
// contacts: Vec<String>,
|
contacts: Vec<String>,
|
||||||
client_name: Option<String>,
|
client_name: Option<String>,
|
||||||
logo_uri: Option<String>,
|
logo_uri: Option<String>,
|
||||||
client_uri: Option<String>,
|
client_uri: Option<String>,
|
||||||
@ -92,6 +94,17 @@ impl TryInto<Client> for OAuth2ClientLookup {
|
|||||||
.source(e)
|
.source(e)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let application_type = self
|
||||||
|
.application_type
|
||||||
|
.map(|s| s.parse())
|
||||||
|
.transpose()
|
||||||
|
.map_err(|e| {
|
||||||
|
DatabaseInconsistencyError::on("oauth2_clients")
|
||||||
|
.column("application_type")
|
||||||
|
.row(id)
|
||||||
|
.source(e)
|
||||||
|
})?;
|
||||||
|
|
||||||
let response_types = vec![
|
let response_types = vec![
|
||||||
OAuthAuthorizationEndpointResponseType::Code,
|
OAuthAuthorizationEndpointResponseType::Code,
|
||||||
OAuthAuthorizationEndpointResponseType::IdToken,
|
OAuthAuthorizationEndpointResponseType::IdToken,
|
||||||
@ -237,11 +250,11 @@ impl TryInto<Client> for OAuth2ClientLookup {
|
|||||||
id,
|
id,
|
||||||
client_id: id.to_string(),
|
client_id: id.to_string(),
|
||||||
encrypted_client_secret: self.encrypted_client_secret,
|
encrypted_client_secret: self.encrypted_client_secret,
|
||||||
|
application_type,
|
||||||
redirect_uris,
|
redirect_uris,
|
||||||
response_types,
|
response_types,
|
||||||
grant_types,
|
grant_types,
|
||||||
// contacts: self.contacts,
|
contacts: self.contacts,
|
||||||
contacts: vec![],
|
|
||||||
client_name: self.client_name,
|
client_name: self.client_name,
|
||||||
logo_uri,
|
logo_uri,
|
||||||
client_uri,
|
client_uri,
|
||||||
@ -276,13 +289,11 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
r#"
|
r#"
|
||||||
SELECT oauth2_client_id
|
SELECT oauth2_client_id
|
||||||
, encrypted_client_secret
|
, encrypted_client_secret
|
||||||
, ARRAY(
|
, application_type
|
||||||
SELECT redirect_uri
|
, redirect_uris
|
||||||
FROM oauth2_client_redirect_uris r
|
|
||||||
WHERE r.oauth2_client_id = c.oauth2_client_id
|
|
||||||
) AS "redirect_uris!"
|
|
||||||
, grant_type_authorization_code
|
, grant_type_authorization_code
|
||||||
, grant_type_refresh_token
|
, grant_type_refresh_token
|
||||||
|
, contacts
|
||||||
, client_name
|
, client_name
|
||||||
, logo_uri
|
, logo_uri
|
||||||
, client_uri
|
, client_uri
|
||||||
@ -328,13 +339,11 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
r#"
|
r#"
|
||||||
SELECT oauth2_client_id
|
SELECT oauth2_client_id
|
||||||
, encrypted_client_secret
|
, encrypted_client_secret
|
||||||
, ARRAY(
|
, application_type
|
||||||
SELECT redirect_uri
|
, redirect_uris
|
||||||
FROM oauth2_client_redirect_uris r
|
|
||||||
WHERE r.oauth2_client_id = c.oauth2_client_id
|
|
||||||
) AS "redirect_uris!"
|
|
||||||
, grant_type_authorization_code
|
, grant_type_authorization_code
|
||||||
, grant_type_refresh_token
|
, grant_type_refresh_token
|
||||||
|
, contacts
|
||||||
, client_name
|
, client_name
|
||||||
, logo_uri
|
, logo_uri
|
||||||
, client_uri
|
, client_uri
|
||||||
@ -379,10 +388,11 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
async fn add(
|
async fn add(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut rng: &mut (dyn RngCore + Send),
|
rng: &mut (dyn RngCore + Send),
|
||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
redirect_uris: Vec<Url>,
|
redirect_uris: Vec<Url>,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
|
application_type: Option<ApplicationType>,
|
||||||
grant_types: Vec<GrantType>,
|
grant_types: Vec<GrantType>,
|
||||||
contacts: Vec<String>,
|
contacts: Vec<String>,
|
||||||
client_name: Option<String>,
|
client_name: Option<String>,
|
||||||
@ -408,11 +418,15 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
.transpose()
|
.transpose()
|
||||||
.map_err(DatabaseError::to_invalid_operation)?;
|
.map_err(DatabaseError::to_invalid_operation)?;
|
||||||
|
|
||||||
|
let redirect_uris_array = redirect_uris.iter().map(Url::to_string).collect::<Vec<_>>();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO oauth2_clients
|
INSERT INTO oauth2_clients
|
||||||
( oauth2_client_id
|
( oauth2_client_id
|
||||||
, encrypted_client_secret
|
, encrypted_client_secret
|
||||||
|
, application_type
|
||||||
|
, redirect_uris
|
||||||
, grant_type_authorization_code
|
, grant_type_authorization_code
|
||||||
, grant_type_refresh_token
|
, grant_type_refresh_token
|
||||||
, client_name
|
, client_name
|
||||||
@ -430,10 +444,12 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
, is_static
|
, is_static
|
||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, FALSE)
|
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, FALSE)
|
||||||
"#,
|
"#,
|
||||||
Uuid::from(id),
|
Uuid::from(id),
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
application_type.map(|a| a.to_string()),
|
||||||
|
&redirect_uris_array,
|
||||||
grant_types.contains(&GrantType::AuthorizationCode),
|
grant_types.contains(&GrantType::AuthorizationCode),
|
||||||
grant_types.contains(&GrantType::RefreshToken),
|
grant_types.contains(&GrantType::RefreshToken),
|
||||||
client_name,
|
client_name,
|
||||||
@ -459,40 +475,6 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
.execute(&mut *self.conn)
|
.execute(&mut *self.conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
{
|
|
||||||
let span = info_span!(
|
|
||||||
"db.oauth2_client.add.redirect_uris",
|
|
||||||
db.statement = tracing::field::Empty,
|
|
||||||
client.id = %id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (uri_ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
|
||||||
.iter()
|
|
||||||
.map(|uri| {
|
|
||||||
(
|
|
||||||
Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut rng)),
|
|
||||||
uri.as_str().to_owned(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.unzip();
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO oauth2_client_redirect_uris
|
|
||||||
(oauth2_client_redirect_uri_id, oauth2_client_id, redirect_uri)
|
|
||||||
SELECT id, $2, redirect_uri
|
|
||||||
FROM UNNEST($1::uuid[], $3::text[]) r(id, redirect_uri)
|
|
||||||
"#,
|
|
||||||
&uri_ids,
|
|
||||||
Uuid::from(id),
|
|
||||||
&redirect_uris,
|
|
||||||
)
|
|
||||||
.record(&span)
|
|
||||||
.execute(&mut *self.conn)
|
|
||||||
.instrument(span)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let jwks = match (jwks, jwks_uri) {
|
let jwks = match (jwks, jwks_uri) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(Some(jwks), None) => Some(JwksOrJwksUri::Jwks(jwks)),
|
(Some(jwks), None) => Some(JwksOrJwksUri::Jwks(jwks)),
|
||||||
@ -504,6 +486,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
id,
|
id,
|
||||||
client_id: id.to_string(),
|
client_id: id.to_string(),
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
application_type,
|
||||||
redirect_uris,
|
redirect_uris,
|
||||||
response_types: vec![
|
response_types: vec![
|
||||||
OAuthAuthorizationEndpointResponseType::Code,
|
OAuthAuthorizationEndpointResponseType::Code,
|
||||||
@ -537,8 +520,6 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
)]
|
)]
|
||||||
async fn upsert_static(
|
async fn upsert_static(
|
||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut (dyn RngCore + Send),
|
|
||||||
clock: &dyn Clock,
|
|
||||||
client_id: Ulid,
|
client_id: Ulid,
|
||||||
client_auth_method: OAuthClientAuthenticationMethod,
|
client_auth_method: OAuthClientAuthenticationMethod,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
@ -553,12 +534,14 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
.map_err(DatabaseError::to_invalid_operation)?;
|
.map_err(DatabaseError::to_invalid_operation)?;
|
||||||
|
|
||||||
let client_auth_method = client_auth_method.to_string();
|
let client_auth_method = client_auth_method.to_string();
|
||||||
|
let redirect_uris_array = redirect_uris.iter().map(Url::to_string).collect::<Vec<_>>();
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO oauth2_clients
|
INSERT INTO oauth2_clients
|
||||||
( oauth2_client_id
|
( oauth2_client_id
|
||||||
, encrypted_client_secret
|
, encrypted_client_secret
|
||||||
|
, redirect_uris
|
||||||
, grant_type_authorization_code
|
, grant_type_authorization_code
|
||||||
, grant_type_refresh_token
|
, grant_type_refresh_token
|
||||||
, token_endpoint_auth_method
|
, token_endpoint_auth_method
|
||||||
@ -567,7 +550,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
, is_static
|
, is_static
|
||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
($1, $2, $3, $4, $5, $6, $7, TRUE)
|
($1, $2, $3, $4, $5, $6, $7, $8, TRUE)
|
||||||
ON CONFLICT (oauth2_client_id)
|
ON CONFLICT (oauth2_client_id)
|
||||||
DO
|
DO
|
||||||
UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret
|
UPDATE SET encrypted_client_secret = EXCLUDED.encrypted_client_secret
|
||||||
@ -580,6 +563,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
"#,
|
"#,
|
||||||
Uuid::from(client_id),
|
Uuid::from(client_id),
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
&redirect_uris_array,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
client_auth_method,
|
client_auth_method,
|
||||||
@ -590,41 +574,6 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
.execute(&mut *self.conn)
|
.execute(&mut *self.conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
{
|
|
||||||
let span = info_span!(
|
|
||||||
"db.oauth2_client.upsert_static.redirect_uris",
|
|
||||||
client.id = %client_id,
|
|
||||||
db.statement = tracing::field::Empty,
|
|
||||||
);
|
|
||||||
|
|
||||||
let now = clock.now();
|
|
||||||
let (ids, redirect_uris): (Vec<Uuid>, Vec<String>) = redirect_uris
|
|
||||||
.iter()
|
|
||||||
.map(|uri| {
|
|
||||||
(
|
|
||||||
Uuid::from(Ulid::from_datetime_with_source(now.into(), &mut *rng)),
|
|
||||||
uri.as_str().to_owned(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.unzip();
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
INSERT INTO oauth2_client_redirect_uris
|
|
||||||
(oauth2_client_redirect_uri_id, oauth2_client_id, redirect_uri)
|
|
||||||
SELECT id, $2, redirect_uri
|
|
||||||
FROM UNNEST($1::uuid[], $3::text[]) r(id, redirect_uri)
|
|
||||||
"#,
|
|
||||||
&ids,
|
|
||||||
Uuid::from(client_id),
|
|
||||||
&redirect_uris,
|
|
||||||
)
|
|
||||||
.record(&span)
|
|
||||||
.execute(&mut *self.conn)
|
|
||||||
.instrument(span)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let jwks = match (jwks, jwks_uri) {
|
let jwks = match (jwks, jwks_uri) {
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
(Some(jwks), None) => Some(JwksOrJwksUri::Jwks(jwks)),
|
(Some(jwks), None) => Some(JwksOrJwksUri::Jwks(jwks)),
|
||||||
@ -636,6 +585,7 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
id: client_id,
|
id: client_id,
|
||||||
client_id: client_id.to_string(),
|
client_id: client_id.to_string(),
|
||||||
encrypted_client_secret,
|
encrypted_client_secret,
|
||||||
|
application_type: None,
|
||||||
redirect_uris,
|
redirect_uris,
|
||||||
response_types: vec![
|
response_types: vec![
|
||||||
OAuthAuthorizationEndpointResponseType::Code,
|
OAuthAuthorizationEndpointResponseType::Code,
|
||||||
@ -672,13 +622,11 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
r#"
|
r#"
|
||||||
SELECT oauth2_client_id
|
SELECT oauth2_client_id
|
||||||
, encrypted_client_secret
|
, encrypted_client_secret
|
||||||
, ARRAY(
|
, application_type
|
||||||
SELECT redirect_uri
|
, redirect_uris
|
||||||
FROM oauth2_client_redirect_uris r
|
|
||||||
WHERE r.oauth2_client_id = c.oauth2_client_id
|
|
||||||
) AS "redirect_uris!"
|
|
||||||
, grant_type_authorization_code
|
, grant_type_authorization_code
|
||||||
, grant_type_refresh_token
|
, grant_type_refresh_token
|
||||||
|
, contacts
|
||||||
, client_name
|
, client_name
|
||||||
, logo_uri
|
, logo_uri
|
||||||
, client_uri
|
, client_uri
|
||||||
@ -911,26 +859,6 @@ impl<'c> OAuth2ClientRepository for PgOAuth2ClientRepository<'c> {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the redirect URIs
|
|
||||||
{
|
|
||||||
let span = info_span!(
|
|
||||||
"db.oauth2_client.delete_by_id.redirect_uris",
|
|
||||||
db.statement = tracing::field::Empty,
|
|
||||||
);
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
r#"
|
|
||||||
DELETE FROM oauth2_client_redirect_uris
|
|
||||||
WHERE oauth2_client_id = $1
|
|
||||||
"#,
|
|
||||||
Uuid::from(id),
|
|
||||||
)
|
|
||||||
.record(&span)
|
|
||||||
.execute(&mut *self.conn)
|
|
||||||
.instrument(span)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now delete the client itself
|
// Now delete the client itself
|
||||||
let res = sqlx::query!(
|
let res = sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -73,6 +73,7 @@ mod tests {
|
|||||||
&clock,
|
&clock,
|
||||||
vec!["https://example.com/redirect".parse().unwrap()],
|
vec!["https://example.com/redirect".parse().unwrap()],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
vec![GrantType::AuthorizationCode],
|
vec![GrantType::AuthorizationCode],
|
||||||
Vec::new(), // TODO: contacts are not yet saved
|
Vec::new(), // TODO: contacts are not yet saved
|
||||||
// vec!["contact@example.com".to_owned()],
|
// vec!["contact@example.com".to_owned()],
|
||||||
@ -409,6 +410,7 @@ mod tests {
|
|||||||
&clock,
|
&clock,
|
||||||
vec!["https://first.example.com/redirect".parse().unwrap()],
|
vec!["https://first.example.com/redirect".parse().unwrap()],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
vec![GrantType::AuthorizationCode],
|
vec![GrantType::AuthorizationCode],
|
||||||
Vec::new(), // TODO: contacts are not yet saved
|
Vec::new(), // TODO: contacts are not yet saved
|
||||||
// vec!["contact@first.example.com".to_owned()],
|
// vec!["contact@first.example.com".to_owned()],
|
||||||
@ -434,6 +436,7 @@ mod tests {
|
|||||||
&clock,
|
&clock,
|
||||||
vec!["https://second.example.com/redirect".parse().unwrap()],
|
vec!["https://second.example.com/redirect".parse().unwrap()],
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
vec![GrantType::AuthorizationCode],
|
vec![GrantType::AuthorizationCode],
|
||||||
Vec::new(), // TODO: contacts are not yet saved
|
Vec::new(), // TODO: contacts are not yet saved
|
||||||
// vec!["contact@second.example.com".to_owned()],
|
// vec!["contact@second.example.com".to_owned()],
|
||||||
|
@ -18,7 +18,7 @@ use async_trait::async_trait;
|
|||||||
use mas_data_model::{Client, User};
|
use mas_data_model::{Client, User};
|
||||||
use mas_iana::{jose::JsonWebSignatureAlg, oauth::OAuthClientAuthenticationMethod};
|
use mas_iana::{jose::JsonWebSignatureAlg, oauth::OAuthClientAuthenticationMethod};
|
||||||
use mas_jose::jwk::PublicJsonWebKeySet;
|
use mas_jose::jwk::PublicJsonWebKeySet;
|
||||||
use oauth2_types::{requests::GrantType, scope::Scope};
|
use oauth2_types::{oidc::ApplicationType, requests::GrantType, scope::Scope};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
@ -80,6 +80,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
|||||||
/// * `clock`: The clock used to generate timestamps
|
/// * `clock`: The clock used to generate timestamps
|
||||||
/// * `redirect_uris`: The list of redirect URIs used by this client
|
/// * `redirect_uris`: The list of redirect URIs used by this client
|
||||||
/// * `encrypted_client_secret`: The encrypted client secret, if any
|
/// * `encrypted_client_secret`: The encrypted client secret, if any
|
||||||
|
/// * `application_type`: The application type of this client
|
||||||
/// * `grant_types`: The list of grant types this client can use
|
/// * `grant_types`: The list of grant types this client can use
|
||||||
/// * `contacts`: The list of contacts for this client
|
/// * `contacts`: The list of contacts for this client
|
||||||
/// * `client_name`: The human-readable name of this client, if given
|
/// * `client_name`: The human-readable name of this client, if given
|
||||||
@ -110,6 +111,7 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
|||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
redirect_uris: Vec<Url>,
|
redirect_uris: Vec<Url>,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
|
application_type: Option<ApplicationType>,
|
||||||
grant_types: Vec<GrantType>,
|
grant_types: Vec<GrantType>,
|
||||||
contacts: Vec<String>,
|
contacts: Vec<String>,
|
||||||
client_name: Option<String>,
|
client_name: Option<String>,
|
||||||
@ -132,8 +134,6 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
/// * `rng`: The random number generator to use
|
|
||||||
/// * `clock`: The clock used to generate timestamps
|
|
||||||
/// * `client_id`: The client ID
|
/// * `client_id`: The client ID
|
||||||
/// * `client_auth_method`: The authentication method this client uses
|
/// * `client_auth_method`: The authentication method this client uses
|
||||||
/// * `encrypted_client_secret`: The encrypted client secret, if any
|
/// * `encrypted_client_secret`: The encrypted client secret, if any
|
||||||
@ -147,8 +147,6 @@ pub trait OAuth2ClientRepository: Send + Sync {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
async fn upsert_static(
|
async fn upsert_static(
|
||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut (dyn RngCore + Send),
|
|
||||||
clock: &dyn Clock,
|
|
||||||
client_id: Ulid,
|
client_id: Ulid,
|
||||||
client_auth_method: OAuthClientAuthenticationMethod,
|
client_auth_method: OAuthClientAuthenticationMethod,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
@ -244,6 +242,7 @@ repository_impl!(OAuth2ClientRepository:
|
|||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
redirect_uris: Vec<Url>,
|
redirect_uris: Vec<Url>,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
|
application_type: Option<ApplicationType>,
|
||||||
grant_types: Vec<GrantType>,
|
grant_types: Vec<GrantType>,
|
||||||
contacts: Vec<String>,
|
contacts: Vec<String>,
|
||||||
client_name: Option<String>,
|
client_name: Option<String>,
|
||||||
@ -262,8 +261,6 @@ repository_impl!(OAuth2ClientRepository:
|
|||||||
|
|
||||||
async fn upsert_static(
|
async fn upsert_static(
|
||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut (dyn RngCore + Send),
|
|
||||||
clock: &dyn Clock,
|
|
||||||
client_id: Ulid,
|
client_id: Ulid,
|
||||||
client_auth_method: OAuthClientAuthenticationMethod,
|
client_auth_method: OAuthClientAuthenticationMethod,
|
||||||
encrypted_client_secret: Option<String>,
|
encrypted_client_secret: Option<String>,
|
||||||
|
@ -475,6 +475,20 @@ interface Node {
|
|||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
The application type advertised by the client.
|
||||||
|
"""
|
||||||
|
enum Oauth2ApplicationType {
|
||||||
|
"""
|
||||||
|
Client is a web application.
|
||||||
|
"""
|
||||||
|
WEB
|
||||||
|
"""
|
||||||
|
Client is a native application.
|
||||||
|
"""
|
||||||
|
NATIVE
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
An OAuth 2.0 client
|
An OAuth 2.0 client
|
||||||
"""
|
"""
|
||||||
@ -507,6 +521,14 @@ type Oauth2Client implements Node {
|
|||||||
List of redirect URIs used for authorization grants by the client.
|
List of redirect URIs used for authorization grants by the client.
|
||||||
"""
|
"""
|
||||||
redirectUris: [Url!]!
|
redirectUris: [Url!]!
|
||||||
|
"""
|
||||||
|
List of contacts advertised by the client.
|
||||||
|
"""
|
||||||
|
contacts: [String!]!
|
||||||
|
"""
|
||||||
|
The application type advertised by the client.
|
||||||
|
"""
|
||||||
|
applicationType: Oauth2ApplicationType
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -382,15 +382,27 @@ export type Node = {
|
|||||||
id: Scalars["ID"]["output"];
|
id: Scalars["ID"]["output"];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** The application type advertised by the client. */
|
||||||
|
export enum Oauth2ApplicationType {
|
||||||
|
/** Client is a native application. */
|
||||||
|
Native = "NATIVE",
|
||||||
|
/** Client is a web application. */
|
||||||
|
Web = "WEB",
|
||||||
|
}
|
||||||
|
|
||||||
/** An OAuth 2.0 client */
|
/** An OAuth 2.0 client */
|
||||||
export type Oauth2Client = Node & {
|
export type Oauth2Client = Node & {
|
||||||
__typename?: "Oauth2Client";
|
__typename?: "Oauth2Client";
|
||||||
|
/** The application type advertised by the client. */
|
||||||
|
applicationType?: Maybe<Oauth2ApplicationType>;
|
||||||
/** OAuth 2.0 client ID */
|
/** OAuth 2.0 client ID */
|
||||||
clientId: Scalars["String"]["output"];
|
clientId: Scalars["String"]["output"];
|
||||||
/** Client name advertised by the client. */
|
/** Client name advertised by the client. */
|
||||||
clientName?: Maybe<Scalars["String"]["output"]>;
|
clientName?: Maybe<Scalars["String"]["output"]>;
|
||||||
/** Client URI advertised by the client. */
|
/** Client URI advertised by the client. */
|
||||||
clientUri?: Maybe<Scalars["Url"]["output"]>;
|
clientUri?: Maybe<Scalars["Url"]["output"]>;
|
||||||
|
/** List of contacts advertised by the client. */
|
||||||
|
contacts: Array<Scalars["String"]["output"]>;
|
||||||
/** ID of the object. */
|
/** ID of the object. */
|
||||||
id: Scalars["ID"]["output"];
|
id: Scalars["ID"]["output"];
|
||||||
/** Privacy policy URI advertised by the client. */
|
/** Privacy policy URI advertised by the client. */
|
||||||
|
@ -1046,6 +1046,14 @@ export default {
|
|||||||
kind: "OBJECT",
|
kind: "OBJECT",
|
||||||
name: "Oauth2Client",
|
name: "Oauth2Client",
|
||||||
fields: [
|
fields: [
|
||||||
|
{
|
||||||
|
name: "applicationType",
|
||||||
|
type: {
|
||||||
|
kind: "SCALAR",
|
||||||
|
name: "Any",
|
||||||
|
},
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "clientId",
|
name: "clientId",
|
||||||
type: {
|
type: {
|
||||||
@ -1073,6 +1081,23 @@ export default {
|
|||||||
},
|
},
|
||||||
args: [],
|
args: [],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "contacts",
|
||||||
|
type: {
|
||||||
|
kind: "NON_NULL",
|
||||||
|
ofType: {
|
||||||
|
kind: "LIST",
|
||||||
|
ofType: {
|
||||||
|
kind: "NON_NULL",
|
||||||
|
ofType: {
|
||||||
|
kind: "SCALAR",
|
||||||
|
name: "Any",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "id",
|
||||||
type: {
|
type: {
|
||||||
|
Reference in New Issue
Block a user