Check for single and multiple token audiences (#4493)
This commit is contained in:
parent
89f1de825a
commit
a8b96936f4
1 changed files with 461 additions and 16 deletions
|
@ -2266,7 +2266,87 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
assert!(res.is_ok(), "Failed to signin with token: {:?}", res);
|
||||
assert_eq!(sess.ns, Some("test".to_string()));
|
||||
assert_eq!(sess.db, Some("test".to_string()));
|
||||
assert_eq!(sess.ac, Some("user".to_string()));
|
||||
assert!(sess.au.is_db());
|
||||
assert_eq!(sess.au.level().ns(), Some("test"));
|
||||
assert_eq!(sess.au.level().db(), Some("test"));
|
||||
// Record users should not have roles
|
||||
assert!(sess.au.has_role(&Role::Viewer), "Auth user expected to have Viewer role");
|
||||
assert!(!sess.au.has_role(&Role::Editor), "Auth user expected to not have Editor role");
|
||||
assert!(!sess.au.has_role(&Role::Owner), "Auth user expected to not have Owner role");
|
||||
// Expiration should match the defined duration
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to follow the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test with correct "iss" and "aud" claims, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"invalid".to_string(),
|
||||
"surrealdb-test".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ns: Some("test".to_string()),
|
||||
db: Some("test".to_string()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test").with_db("test");
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON DATABASE TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2335,7 +2415,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2358,7 +2442,7 @@ mod tests {
|
|||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience" => {} // ok
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience string" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience, but instead received: {:?}",
|
||||
res
|
||||
|
@ -2366,6 +2450,68 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"surrealdb-test-different".to_string(),
|
||||
"invalid".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ns: Some("test".to_string()),
|
||||
db: Some("test".to_string()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test").with_db("test");
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON DATABASE TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience array" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience array, but instead received: {:?}",
|
||||
res
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim
|
||||
// In this case, something is returned by the clause, which returns a generic error
|
||||
{
|
||||
|
@ -2392,7 +2538,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF $token.aud != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ RETURN "FAIL" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ RETURN "FAIL" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2450,7 +2600,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2493,6 +2647,81 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
// Test with correct "iss" and "aud" claims, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"invalid".to_string(),
|
||||
"surrealdb-test".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ns: Some("test".to_string()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test");
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON NAMESPACE TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
assert!(res.is_ok(), "Failed to signin with token: {:?}", res);
|
||||
assert_eq!(sess.ns, Some("test".to_string()));
|
||||
assert_eq!(sess.db, None);
|
||||
assert_eq!(sess.ac, Some("user".to_string()));
|
||||
assert!(sess.au.is_ns());
|
||||
assert_eq!(sess.au.level().ns(), Some("test"));
|
||||
assert_eq!(sess.au.level().db(), None);
|
||||
// Record users should not have roles
|
||||
assert!(sess.au.has_role(&Role::Viewer), "Auth user expected to have Viewer role");
|
||||
assert!(!sess.au.has_role(&Role::Editor), "Auth user expected to not have Editor role");
|
||||
assert!(!sess.au.has_role(&Role::Owner), "Auth user expected to not have Owner role");
|
||||
// Expiration should match the defined duration
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to follow the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
|
@ -2517,7 +2746,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2540,7 +2773,7 @@ mod tests {
|
|||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience" => {} // ok
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience string" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience, but instead received: {:?}",
|
||||
res
|
||||
|
@ -2548,6 +2781,68 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"surrealdb-test-different".to_string(),
|
||||
"invalid".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ns: Some("test".to_string()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner().with_ns("test");
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON NAMESPACE TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience array" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience array, but instead received: {:?}",
|
||||
res
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim
|
||||
// In this case, something is returned by the clause, which returns a generic error
|
||||
{
|
||||
|
@ -2573,7 +2868,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF $token.aud != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ RETURN "FAIL" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ RETURN "FAIL" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2630,7 +2929,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2672,6 +2975,80 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
// Test with correct "iss" and "aud" claims, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"invalid".to_string(),
|
||||
"surrealdb-test".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner();
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON ROOT TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
assert!(res.is_ok(), "Failed to signin with token: {:?}", res);
|
||||
assert_eq!(sess.ns, None);
|
||||
assert_eq!(sess.db, None);
|
||||
assert_eq!(sess.ac, Some("user".to_string()));
|
||||
assert!(sess.au.is_root());
|
||||
assert_eq!(sess.au.level().ns(), None);
|
||||
assert_eq!(sess.au.level().db(), None);
|
||||
// Record users should not have roles
|
||||
assert!(sess.au.has_role(&Role::Viewer), "Auth user expected to have Viewer role");
|
||||
assert!(!sess.au.has_role(&Role::Editor), "Auth user expected to not have Editor role");
|
||||
assert!(!sess.au.has_role(&Role::Owner), "Auth user expected to not have Owner role");
|
||||
// Expiration should match the defined duration
|
||||
let exp = sess.exp.unwrap();
|
||||
// Expiration should match the current time plus session duration with some margin
|
||||
let min_exp = (Utc::now() + Duration::hours(2) - Duration::seconds(10)).timestamp();
|
||||
let max_exp = (Utc::now() + Duration::hours(2) + Duration::seconds(10)).timestamp();
|
||||
assert!(
|
||||
exp > min_exp && exp < max_exp,
|
||||
"Session expiration is expected to follow the defined duration"
|
||||
);
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
|
@ -2695,7 +3072,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF $token.aud != "surrealdb-test" {{ THROW "Invalid token audience" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
@ -2718,7 +3099,7 @@ mod tests {
|
|||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience" => {} // ok
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience string" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience, but instead received: {:?}",
|
||||
res
|
||||
|
@ -2726,6 +3107,66 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim, with multiple audiences
|
||||
{
|
||||
let secret = "jwt_secret";
|
||||
let key = EncodingKey::from_secret(secret.as_ref());
|
||||
let claims = Claims {
|
||||
iss: Some("surrealdb-test".to_string()),
|
||||
aud: Some(Audience::Multiple(vec![
|
||||
"surrealdb-test-different".to_string(),
|
||||
"invalid".to_string(),
|
||||
])),
|
||||
iat: Some(Utc::now().timestamp()),
|
||||
nbf: Some(Utc::now().timestamp()),
|
||||
exp: Some((Utc::now() + Duration::hours(1)).timestamp()),
|
||||
ac: Some("user".to_string()),
|
||||
..Claims::default()
|
||||
};
|
||||
|
||||
let ds = Datastore::new("memory").await.unwrap();
|
||||
let sess = Session::owner();
|
||||
ds.execute(
|
||||
format!(
|
||||
r#"
|
||||
DEFINE ACCESS user ON ROOT TYPE JWT
|
||||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ THROW "Invalid token issuer" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ THROW "Invalid token audience array" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ THROW "Invalid token audience string" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
"#
|
||||
)
|
||||
.as_str(),
|
||||
&sess,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Prepare the claims object
|
||||
let mut claims = claims.clone();
|
||||
claims.roles = None;
|
||||
// Create the token
|
||||
let enc = encode(&HEADER, &claims, &key).unwrap();
|
||||
// Signin with the token
|
||||
let mut sess = Session::default();
|
||||
let res = token(&ds, &mut sess, &enc).await;
|
||||
|
||||
match res {
|
||||
Err(Error::Thrown(e)) if e == "Invalid token audience array" => {} // ok
|
||||
res => panic!(
|
||||
"Expected authentication to failed due to invalid token audience array, but instead received: {:?}",
|
||||
res
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Test with correct "iss" claim but incorrect "aud" claim
|
||||
// In this case, something is returned by the clause, which returns a generic error
|
||||
{
|
||||
|
@ -2750,7 +3191,11 @@ mod tests {
|
|||
ALGORITHM HS512 KEY '{secret}'
|
||||
AUTHENTICATE {{
|
||||
IF $token.iss != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF $token.aud != "surrealdb-test" {{ RETURN "FAIL" }};
|
||||
IF type::is::array($token.aud) {{
|
||||
IF "surrealdb-test" NOT IN $token.aud {{ RETURN "FAIL" }}
|
||||
}} ELSE {{
|
||||
IF $token.aud IS NOT "surrealdb-test" {{ RETURN "FAIL" }}
|
||||
}};
|
||||
}}
|
||||
DURATION FOR SESSION 2h
|
||||
;
|
||||
|
|
Loading…
Reference in a new issue