Skip to content

Commit 138fde1

Browse files
feat(oauth,oidc): add regex redirect patterns (#281)
1 parent c2655b2 commit 138fde1

10 files changed

Lines changed: 40 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ leptos_actix = "0.8.3"
5050
leptos_axum = "0.8.3"
5151
leptos_meta = "0.8.3"
5252
leptos_router = "0.8.3"
53+
regex = "1.12.2"
5354
sea-orm = "1.1.2"
5455
sea-orm-migration = "1.1.2"
5556
secrecy = "0.10.3"

packages/core/shield/src/options.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@ use bon::Builder;
22

33
#[derive(Builder, Clone, Debug)]
44
#[builder(on(String, into), state_mod(vis = "pub(crate)"))]
5-
pub struct ShieldOptions {
6-
#[builder(default = "/")]
7-
pub sign_in_redirect: String,
8-
#[builder(default = "/")]
9-
pub sign_out_redirect: String,
10-
}
5+
pub struct ShieldOptions {}
116

127
impl Default for ShieldOptions {
138
fn default() -> Self {
Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use axum::{
22
extract::Request,
33
middleware::Next,
4-
response::{IntoResponse, Redirect, Response},
4+
response::{IntoResponse, Response},
55
};
66
use shield::{ShieldError, User};
77

8-
use crate::{ExtractShield, ExtractUser, error::RouteError};
8+
use crate::{ExtractUser, error::RouteError};
99

1010
pub async fn auth_required<U: User>(
1111
ExtractUser(user): ExtractUser<U>,
@@ -17,15 +17,3 @@ pub async fn auth_required<U: User>(
1717
None => RouteError::from(ShieldError::Unauthorized).into_response(),
1818
}
1919
}
20-
21-
pub async fn auth_required_redirect<U: User>(
22-
ExtractShield(shield): ExtractShield<U>,
23-
ExtractUser(user): ExtractUser<U>,
24-
request: Request,
25-
next: Next,
26-
) -> Response {
27-
match user {
28-
Some(_) => next.run(request).await,
29-
None => Redirect::to(&shield.options().sign_in_redirect).into_response(),
30-
}
31-
}

packages/methods/shield-oauth/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ oauth2 = { version = "5.0.0", default-features = false, features = [
2424
"pkce-plain",
2525
"reqwest",
2626
] }
27+
regex.workspace = true
2728
secrecy.workspace = true
2829
serde.workspace = true
2930
serde_json.workspace = true

packages/methods/shield-oauth/src/actions/sign_in.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ impl Action<OauthProvider, OauthSession> for OauthSignInAction {
110110
}
111111
}
112112

113+
if let Some(redirect_patterns) = &self.options.redirect_patterns {
114+
let redirect_url_str = redirect_url.to_string();
115+
if !redirect_patterns
116+
.iter()
117+
.any(|pattern| pattern.is_match(&redirect_url_str))
118+
{
119+
return Err(ShieldError::Validation(format!(
120+
"redirect URL `{redirect_url}` not allowed"
121+
)));
122+
}
123+
}
124+
113125
let client = provider.oauth_client().await?;
114126

115127
let mut authorization_request = client

packages/methods/shield-oauth/src/options.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bon::Builder;
2+
use regex::Regex;
23
use url::Url;
34

45
#[derive(Builder, Clone, Debug)]
@@ -9,6 +10,9 @@ pub struct OauthOptions {
910

1011
#[builder(with = FromIterator::from_iter)]
1112
pub(crate) redirect_origins: Option<Vec<Url>>,
13+
14+
#[builder(with = FromIterator::from_iter)]
15+
pub(crate) redirect_patterns: Option<Vec<Regex>>,
1216
}
1317

1418
impl Default for OauthOptions {

packages/methods/shield-oidc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ oauth2 = { version = "5.0.0", default-features = false, features = [
2626
openidconnect = { version = "4.0.0", default-features = false, features = [
2727
"reqwest",
2828
] }
29+
regex.workspace = true
2930
secrecy.workspace = true
3031
serde.workspace = true
3132
serde_json.workspace = true

packages/methods/shield-oidc/src/actions/sign_in.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ impl Action<OidcProvider, OidcSession> for OidcSignInAction {
113113
}
114114
}
115115

116+
if let Some(redirect_patterns) = &self.options.redirect_patterns {
117+
let redirect_url_str = redirect_url.to_string();
118+
if !redirect_patterns
119+
.iter()
120+
.any(|pattern| pattern.is_match(&redirect_url_str))
121+
{
122+
return Err(ShieldError::Validation(format!(
123+
"redirect URL `{redirect_url}` not allowed"
124+
)));
125+
}
126+
}
127+
116128
let client = provider.oidc_client().await?;
117129

118130
let mut authorization_request = client.authorize_url(

packages/methods/shield-oidc/src/options.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bon::Builder;
2+
use regex::Regex;
23
use url::Url;
34

45
#[derive(Builder, Clone, Debug)]
@@ -9,6 +10,9 @@ pub struct OidcOptions {
910

1011
#[builder(with = FromIterator::from_iter)]
1112
pub(crate) redirect_origins: Option<Vec<Url>>,
13+
14+
#[builder(with = FromIterator::from_iter)]
15+
pub(crate) redirect_patterns: Option<Vec<Regex>>,
1216
}
1317

1418
impl Default for OidcOptions {

0 commit comments

Comments
 (0)