Develop first version (#1)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Create first version of the library The code is mainly taken from * https://gitea.communiquons.org/pierre/oidc-test-client * https://gitea.communiquons.org/pierre/BasicOIDC with little improvements. Reviewed-on: #1
This commit is contained in:
82
src/client.rs
Normal file
82
src/client.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
//! # Open ID client implementation
|
||||
|
||||
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
|
||||
use crate::primitives::{OpenIDConfig, OpenIDTokenResponse, OpenIDUserInfo};
|
||||
|
||||
impl OpenIDConfig {
|
||||
/// Load OpenID configuration from a given .well-known/openid-configuration URL
|
||||
pub async fn load_from_url(url: &str) -> Result<Self, Box<dyn Error>> {
|
||||
Ok(reqwest::get(url).await?.json().await?)
|
||||
}
|
||||
|
||||
/// Get the authorization URL where a user should be redirect to perform authentication
|
||||
pub fn gen_authorization_url(
|
||||
&self,
|
||||
client_id: &str,
|
||||
state: &str,
|
||||
redirect_uri: &str,
|
||||
) -> String {
|
||||
let client_id = urlencoding::encode(client_id);
|
||||
let state = urlencoding::encode(state);
|
||||
let redirect_uri = urlencoding::encode(redirect_uri);
|
||||
|
||||
format!("{}?response_type=code&scope=openid%20profile%20email&client_id={client_id}&state={state}&redirect_uri={redirect_uri}", self.authorization_endpoint)
|
||||
}
|
||||
|
||||
/// Query the token endpoint
|
||||
///
|
||||
/// This endpoint returns both the parsed and the raw response, to allow handling
|
||||
/// of bonus fields
|
||||
pub async fn request_token(
|
||||
&self,
|
||||
client_id: &str,
|
||||
client_secret: &str,
|
||||
code: &str,
|
||||
redirect_uri: &str,
|
||||
) -> Result<(OpenIDTokenResponse, String), Box<dyn Error>> {
|
||||
let authorization = BASE64_STANDARD.encode(format!("{}:{}", client_id, client_secret));
|
||||
|
||||
let mut params = HashMap::new();
|
||||
params.insert("grant_type", "authorization_code");
|
||||
params.insert("code", code);
|
||||
params.insert("redirect_uri", redirect_uri);
|
||||
|
||||
let response = reqwest::Client::new()
|
||||
.post(&self.token_endpoint)
|
||||
.header("Authorization", format!("Basic {authorization}"))
|
||||
.form(¶ms)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
Ok((serde_json::from_str(&response)?, response))
|
||||
}
|
||||
|
||||
/// Query the UserInfo endpoint.
|
||||
///
|
||||
/// This endpoint should be use after having successfully retrieved the token
|
||||
///
|
||||
/// This endpoint returns both the parsed value and the raw response, in case of presence
|
||||
/// of additional fields
|
||||
pub async fn request_user_info(
|
||||
&self,
|
||||
token: &OpenIDTokenResponse,
|
||||
) -> Result<(OpenIDUserInfo, String), Box<dyn Error>> {
|
||||
let response = reqwest::Client::new()
|
||||
.get(self.userinfo_endpoint.as_ref().expect(
|
||||
"This client only support information retrieval through userinfo endpoint!",
|
||||
))
|
||||
.header("Authorization", format!("Bearer {}", token.access_token))
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
|
||||
Ok((serde_json::from_str(&response)?, response))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user