Add implicit authentication flow #255
@ -97,7 +97,7 @@ pub struct AuthorizeQuery {
|
|||||||
redirect_uri: String,
|
redirect_uri: String,
|
||||||
|
|
||||||
/// RECOMMENDED. Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.
|
/// RECOMMENDED. Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.
|
||||||
state: String,
|
state: Option<String>,
|
||||||
|
|
||||||
/// OPTIONAL. String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.
|
/// OPTIONAL. String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.
|
||||||
nonce: Option<String>,
|
nonce: Option<String>,
|
||||||
@ -118,11 +118,14 @@ fn error_redirect(query: &AuthorizeQuery, error: &str, description: &str) -> Htt
|
|||||||
.append_header((
|
.append_header((
|
||||||
"Location",
|
"Location",
|
||||||
format!(
|
format!(
|
||||||
"{}?error={}?error_description={}&state={}",
|
"{}?error={}?error_description={}{}",
|
||||||
query.redirect_uri,
|
query.redirect_uri,
|
||||||
urlencoding::encode(error),
|
urlencoding::encode(error),
|
||||||
urlencoding::encode(description),
|
urlencoding::encode(description),
|
||||||
urlencoding::encode(&query.state)
|
match &query.state {
|
||||||
|
Some(s) => format!("&state={}", urlencoding::encode(s)),
|
||||||
|
None => "".to_string(),
|
||||||
|
}
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
.finish()
|
.finish()
|
||||||
@ -167,8 +170,8 @@ pub async fn authorize(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if query.state.is_empty() {
|
if query.state.as_ref().map(String::is_empty).unwrap_or(false) {
|
||||||
return error_redirect(&query, "invalid_request", "State is empty!");
|
return error_redirect(&query, "invalid_request", "State is specified but empty!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let code_challenge = match query.0.code_challenge.clone() {
|
let code_challenge = match query.0.code_challenge.clone() {
|
||||||
@ -226,9 +229,12 @@ pub async fn authorize(
|
|||||||
.append_header((
|
.append_header((
|
||||||
"Location",
|
"Location",
|
||||||
format!(
|
format!(
|
||||||
"{}?state={}&session_state={}&code={}",
|
"{}?{}session_state={}&code={}",
|
||||||
session.redirect_uri,
|
session.redirect_uri,
|
||||||
urlencoding::encode(&query.0.state),
|
match &query.0.state {
|
||||||
|
Some(state) => format!("state={}&", urlencoding::encode(state)),
|
||||||
|
None => "".to_string(),
|
||||||
|
},
|
||||||
urlencoding::encode(&session.session_id.0),
|
urlencoding::encode(&session.session_id.0),
|
||||||
urlencoding::encode(&session.authorization_code)
|
urlencoding::encode(&session.authorization_code)
|
||||||
),
|
),
|
||||||
@ -344,7 +350,8 @@ pub async fn token(
|
|||||||
.find_by_id(&client_id)
|
.find_by_id(&client_id)
|
||||||
.ok_or_else(|| ErrorUnauthorized("Client not found"))?;
|
.ok_or_else(|| ErrorUnauthorized("Client not found"))?;
|
||||||
|
|
||||||
if !client.secret.eq(&client_secret) {
|
// Retrieving token requires the client to have a defined secret
|
||||||
|
if client.secret != Some(client_secret) {
|
||||||
return Ok(error_response(
|
return Ok(error_response(
|
||||||
&query,
|
&query,
|
||||||
"invalid_request",
|
"invalid_request",
|
||||||
|
@ -4,6 +4,11 @@ use crate::utils::string_utils::apply_env_vars;
|
|||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
|
||||||
pub struct ClientID(pub String);
|
pub struct ClientID(pub String);
|
||||||
|
|
||||||
|
pub enum AuthenticationFlow {
|
||||||
|
AuthorizationCode,
|
||||||
|
Implicit,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
/// The ID of the client
|
/// The ID of the client
|
||||||
@ -16,7 +21,8 @@ pub struct Client {
|
|||||||
pub description: String,
|
pub description: String,
|
||||||
|
|
||||||
/// The secret used by the client to retrieve authenticated users information
|
/// The secret used by the client to retrieve authenticated users information
|
||||||
pub secret: String,
|
/// This value is absent if implicit authentication flow is used
|
||||||
|
pub secret: Option<String>,
|
||||||
|
|
||||||
/// The URI where the users should be redirected once authenticated
|
/// The URI where the users should be redirected once authenticated
|
||||||
pub redirect_uri: String,
|
pub redirect_uri: String,
|
||||||
@ -42,6 +48,16 @@ impl PartialEq for Client {
|
|||||||
|
|
||||||
impl Eq for Client {}
|
impl Eq for Client {}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
/// Get the client authentication flow
|
||||||
|
pub fn auth_flow(&self) -> AuthenticationFlow {
|
||||||
|
match self.secret {
|
||||||
|
None => AuthenticationFlow::Implicit,
|
||||||
|
Some(_) => AuthenticationFlow::AuthorizationCode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type ClientManager = EntityManager<Client>;
|
pub type ClientManager = EntityManager<Client>;
|
||||||
|
|
||||||
impl EntityManager<Client> {
|
impl EntityManager<Client> {
|
||||||
@ -66,7 +82,7 @@ impl EntityManager<Client> {
|
|||||||
c.id = ClientID(apply_env_vars(&c.id.0));
|
c.id = ClientID(apply_env_vars(&c.id.0));
|
||||||
c.name = apply_env_vars(&c.name);
|
c.name = apply_env_vars(&c.name);
|
||||||
c.description = apply_env_vars(&c.description);
|
c.description = apply_env_vars(&c.description);
|
||||||
c.secret = apply_env_vars(&c.secret);
|
c.secret = c.secret.as_deref().map(apply_env_vars);
|
||||||
c.redirect_uri = apply_env_vars(&c.redirect_uri);
|
c.redirect_uri = apply_env_vars(&c.redirect_uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user