Merge factors type for authentication
This commit is contained in:
@ -2,12 +2,12 @@ use std::fmt::Debug;
|
||||
|
||||
use actix::Addr;
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{HttpRequest, HttpResponse, Responder, web};
|
||||
use actix_web::error::ErrorUnauthorized;
|
||||
use actix_web::{web, HttpRequest, HttpResponse, Responder};
|
||||
|
||||
use crate::actors::{openid_sessions_actor, users_actor};
|
||||
use crate::actors::openid_sessions_actor::{OpenIDSessionsActor, Session, SessionID};
|
||||
use crate::actors::users_actor::UsersActor;
|
||||
use crate::actors::{openid_sessions_actor, users_actor};
|
||||
use crate::constants::*;
|
||||
use crate::controllers::base_controller::build_fatal_error_page;
|
||||
use crate::data::app_config::AppConfig;
|
||||
@ -15,7 +15,7 @@ use crate::data::client::{ClientID, ClientManager};
|
||||
use crate::data::code_challenge::CodeChallenge;
|
||||
use crate::data::current_user::CurrentUser;
|
||||
use crate::data::id_token::IdToken;
|
||||
use crate::data::jwt_signer::{JsonWebKey, JWTSigner};
|
||||
use crate::data::jwt_signer::{JWTSigner, JsonWebKey};
|
||||
use crate::data::open_id_user_info::OpenIDUserInfo;
|
||||
use crate::data::openid_config::OpenIDConfig;
|
||||
use crate::data::session_identity::SessionIdentity;
|
||||
@ -24,7 +24,9 @@ use crate::utils::string_utils::rand_str;
|
||||
use crate::utils::time::time;
|
||||
|
||||
pub async fn get_configuration(req: HttpRequest, app_conf: web::Data<AppConfig>) -> impl Responder {
|
||||
let is_secure_request = req.headers().get("HTTP_X_FORWARDED_PROTO")
|
||||
let is_secure_request = req
|
||||
.headers()
|
||||
.get("HTTP_X_FORWARDED_PROTO")
|
||||
.map(|v| v.to_str().unwrap_or_default().to_lowercase().eq("https"))
|
||||
.unwrap_or(false);
|
||||
|
||||
@ -33,10 +35,14 @@ pub async fn get_configuration(req: HttpRequest, app_conf: web::Data<AppConfig>)
|
||||
Some(s) => s.to_str().unwrap_or_default(),
|
||||
};
|
||||
|
||||
let curr_origin = format!("{}://{}", match is_secure_request {
|
||||
true => "https",
|
||||
false => "http"
|
||||
}, host);
|
||||
let curr_origin = format!(
|
||||
"{}://{}",
|
||||
match is_secure_request {
|
||||
true => "https",
|
||||
false => "http",
|
||||
},
|
||||
host
|
||||
);
|
||||
|
||||
HttpResponse::Ok().json(OpenIDConfig {
|
||||
issuer: app_conf.website_origin.clone(),
|
||||
@ -80,35 +86,43 @@ pub struct AuthorizeQuery {
|
||||
}
|
||||
|
||||
fn error_redirect(query: &AuthorizeQuery, error: &str, description: &str) -> HttpResponse {
|
||||
log::warn!("Failed to process sign in request ({} => {}): {:?}", error, description, query);
|
||||
log::warn!(
|
||||
"Failed to process sign in request ({} => {}): {:?}",
|
||||
error,
|
||||
description,
|
||||
query
|
||||
);
|
||||
HttpResponse::Found()
|
||||
.append_header(
|
||||
("Location", format!(
|
||||
.append_header((
|
||||
"Location",
|
||||
format!(
|
||||
"{}?error={}?error_description={}&state={}",
|
||||
query.redirect_uri,
|
||||
urlencoding::encode(error),
|
||||
urlencoding::encode(description),
|
||||
urlencoding::encode(&query.state)
|
||||
))
|
||||
)
|
||||
),
|
||||
))
|
||||
.finish()
|
||||
}
|
||||
|
||||
pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<AuthorizeQuery>,
|
||||
clients: web::Data<ClientManager>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>) -> impl Responder {
|
||||
pub async fn authorize(
|
||||
user: CurrentUser,
|
||||
id: Identity,
|
||||
query: web::Query<AuthorizeQuery>,
|
||||
clients: web::Data<ClientManager>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
) -> impl Responder {
|
||||
let client = match clients.find_by_id(&query.client_id) {
|
||||
None => {
|
||||
return HttpResponse::BadRequest()
|
||||
.body(build_fatal_error_page("Client is invalid!"));
|
||||
return HttpResponse::BadRequest().body(build_fatal_error_page("Client is invalid!"));
|
||||
}
|
||||
Some(c) => c
|
||||
Some(c) => c,
|
||||
};
|
||||
|
||||
let redirect_uri = query.redirect_uri.trim().to_string();
|
||||
if !redirect_uri.starts_with(&client.redirect_uri) {
|
||||
return HttpResponse::BadRequest()
|
||||
.body(build_fatal_error_page("Redirect URI is invalid!"));
|
||||
return HttpResponse::BadRequest().body(build_fatal_error_page("Redirect URI is invalid!"));
|
||||
}
|
||||
|
||||
if !query.scope.split(' ').any(|x| x == "openid") {
|
||||
@ -116,7 +130,11 @@ pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<Author
|
||||
}
|
||||
|
||||
if !query.response_type.eq("code") {
|
||||
return error_redirect(&query, "invalid_request", "Only code response type is supported!");
|
||||
return error_redirect(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Only code response type is supported!",
|
||||
);
|
||||
}
|
||||
|
||||
if query.state.is_empty() {
|
||||
@ -127,18 +145,27 @@ pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<Author
|
||||
Some(chal) => {
|
||||
let meth = query.0.code_challenge_method.as_deref().unwrap_or("plain");
|
||||
if !meth.eq("S256") && !meth.eq("plain") {
|
||||
return error_redirect(&query, "invalid_request",
|
||||
"Only S256 and plain code challenge methods are supported!");
|
||||
return error_redirect(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Only S256 and plain code challenge methods are supported!",
|
||||
);
|
||||
}
|
||||
Some(CodeChallenge { code_challenge: chal, code_challenge_method: meth.to_string() })
|
||||
Some(CodeChallenge {
|
||||
code_challenge: chal,
|
||||
code_challenge_method: meth.to_string(),
|
||||
})
|
||||
}
|
||||
_ => None
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Check if user is authorized to access the application
|
||||
if !user.can_access_app(&client.id) {
|
||||
return error_redirect(&query, "invalid_request",
|
||||
"User is not authorized to access this application!");
|
||||
return error_redirect(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"User is not authorized to access this application!",
|
||||
);
|
||||
}
|
||||
|
||||
// Save all authentication information in memory
|
||||
@ -157,18 +184,25 @@ pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<Author
|
||||
nonce: query.0.nonce,
|
||||
code_challenge,
|
||||
};
|
||||
sessions.send(openid_sessions_actor::PushNewSession(session.clone())).await.unwrap();
|
||||
sessions
|
||||
.send(openid_sessions_actor::PushNewSession(session.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
log::trace!("New OpenID session: {:#?}", session);
|
||||
|
||||
HttpResponse::Found()
|
||||
.append_header(("Location", format!(
|
||||
"{}?state={}&session_state={}&code={}",
|
||||
session.redirect_uri,
|
||||
urlencoding::encode(&query.0.state),
|
||||
urlencoding::encode(&session.session_id.0),
|
||||
urlencoding::encode(&session.authorization_code)
|
||||
))).finish()
|
||||
.append_header((
|
||||
"Location",
|
||||
format!(
|
||||
"{}?state={}&session_state={}&code={}",
|
||||
session.redirect_uri,
|
||||
urlencoding::encode(&query.0.state),
|
||||
urlencoding::encode(&session.session_id.0),
|
||||
urlencoding::encode(&session.authorization_code)
|
||||
),
|
||||
))
|
||||
.finish()
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
@ -178,12 +212,16 @@ struct ErrorResponse {
|
||||
}
|
||||
|
||||
pub fn error_response<D: Debug>(query: &D, error: &str, description: &str) -> HttpResponse {
|
||||
log::warn!("request failed: {} - {} => '{:#?}'", error, description, query);
|
||||
HttpResponse::BadRequest()
|
||||
.json(ErrorResponse {
|
||||
error: error.to_string(),
|
||||
error_description: description.to_string(),
|
||||
})
|
||||
log::warn!(
|
||||
"request failed: {} - {} => '{:#?}'",
|
||||
error,
|
||||
description,
|
||||
query
|
||||
);
|
||||
HttpResponse::BadRequest().json(ErrorResponse {
|
||||
error: error.to_string(),
|
||||
error_description: description.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
@ -198,7 +236,6 @@ pub struct TokenRefreshTokenQuery {
|
||||
refresh_token: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct TokenQuery {
|
||||
grant_type: String,
|
||||
@ -222,115 +259,175 @@ pub struct TokenResponse {
|
||||
id_token: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn token(req: HttpRequest,
|
||||
query: web::Form<TokenQuery>,
|
||||
clients: web::Data<ClientManager>,
|
||||
app_config: web::Data<AppConfig>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>,
|
||||
jwt_signer: web::Data<JWTSigner>) -> actix_web::Result<HttpResponse> {
|
||||
|
||||
pub async fn token(
|
||||
req: HttpRequest,
|
||||
query: web::Form<TokenQuery>,
|
||||
clients: web::Data<ClientManager>,
|
||||
app_config: web::Data<AppConfig>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>,
|
||||
jwt_signer: web::Data<JWTSigner>,
|
||||
) -> actix_web::Result<HttpResponse> {
|
||||
// Extraction authentication information
|
||||
let authorization_header = req.headers().get("authorization");
|
||||
let (client_id, client_secret) = match (&query.client_id, &query.client_secret, authorization_header) {
|
||||
// post authentication
|
||||
(Some(client_id), Some(client_secret), None) => {
|
||||
(client_id.clone(), client_secret.to_string())
|
||||
}
|
||||
|
||||
// Basic authentication
|
||||
(None, None, Some(v)) => {
|
||||
let token = match v.to_str().unwrap_or_default().strip_prefix("Basic ") {
|
||||
None => {
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
&format!("Authorization header does not start with 'Basic ', got '{:#?}'", v),
|
||||
));
|
||||
}
|
||||
Some(v) => v
|
||||
};
|
||||
|
||||
let decode = String::from_utf8_lossy(&match base64::decode(token) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
log::error!("Failed to decode authorization header: {:?}", e);
|
||||
return Ok(error_response(&query, "invalid_request", "Failed to decode authorization header!"));
|
||||
}
|
||||
}).to_string();
|
||||
|
||||
match decode.split_once(':') {
|
||||
None => (ClientID(decode), "".to_string()),
|
||||
Some((id, secret)) => (ClientID(id.to_string()), secret.to_string())
|
||||
let (client_id, client_secret) =
|
||||
match (&query.client_id, &query.client_secret, authorization_header) {
|
||||
// post authentication
|
||||
(Some(client_id), Some(client_secret), None) => {
|
||||
(client_id.clone(), client_secret.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Ok(error_response(&query, "invalid_request", "Authentication method unknown!"));
|
||||
}
|
||||
};
|
||||
// Basic authentication
|
||||
(None, None, Some(v)) => {
|
||||
let token = match v.to_str().unwrap_or_default().strip_prefix("Basic ") {
|
||||
None => {
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
&format!(
|
||||
"Authorization header does not start with 'Basic ', got '{:#?}'",
|
||||
v
|
||||
),
|
||||
));
|
||||
}
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
let decode = String::from_utf8_lossy(&match base64::decode(token) {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
log::error!("Failed to decode authorization header: {:?}", e);
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Failed to decode authorization header!",
|
||||
));
|
||||
}
|
||||
})
|
||||
.to_string();
|
||||
|
||||
match decode.split_once(':') {
|
||||
None => (ClientID(decode), "".to_string()),
|
||||
Some((id, secret)) => (ClientID(id.to_string()), secret.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Authentication method unknown!",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let client = clients
|
||||
.find_by_id(&client_id)
|
||||
.ok_or_else(|| ErrorUnauthorized("Client not found"))?;
|
||||
|
||||
if !client.secret.eq(&client_secret) {
|
||||
return Ok(error_response(&query, "invalid_request", "Client secret is invalid!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Client secret is invalid!",
|
||||
));
|
||||
}
|
||||
|
||||
let token_response = match (query.grant_type.as_str(),
|
||||
&query.authorization_code_query,
|
||||
&query.refresh_token_query) {
|
||||
let token_response = match (
|
||||
query.grant_type.as_str(),
|
||||
&query.authorization_code_query,
|
||||
&query.refresh_token_query,
|
||||
) {
|
||||
("authorization_code", Some(q), _) => {
|
||||
let mut session: Session = match sessions
|
||||
.send(openid_sessions_actor::FindSessionByAuthorizationCode(q.code.clone()))
|
||||
.await.unwrap()
|
||||
.send(openid_sessions_actor::FindSessionByAuthorizationCode(
|
||||
q.code.clone(),
|
||||
))
|
||||
.await
|
||||
.unwrap()
|
||||
{
|
||||
None => {
|
||||
return Ok(error_response(&query, "invalid_request", "Session not found!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Session not found!",
|
||||
));
|
||||
}
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
if session.client != client.id {
|
||||
return Ok(error_response(&query, "invalid_request", "Client mismatch!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Client mismatch!",
|
||||
));
|
||||
}
|
||||
|
||||
if session.redirect_uri != q.redirect_uri {
|
||||
return Ok(error_response(&query, "invalid_request", "Invalid redirect URI!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Invalid redirect URI!",
|
||||
));
|
||||
}
|
||||
|
||||
if session.authorization_code_expire_at < time() {
|
||||
return Ok(error_response(&query, "invalid_request", "Authorization code expired!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Authorization code expired!",
|
||||
));
|
||||
}
|
||||
|
||||
// Check code challenge, if needed
|
||||
if let Some(chall) = &session.code_challenge {
|
||||
let code_verifier = match &q.code_verifier {
|
||||
None => {
|
||||
return Ok(error_response(&query, "access_denied", "Code verifier missing"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"access_denied",
|
||||
"Code verifier missing",
|
||||
));
|
||||
}
|
||||
Some(s) => s
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
if !chall.verify_code(code_verifier) {
|
||||
return Ok(error_response(&query, "invalid_grant", "Invalid code verifier"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_grant",
|
||||
"Invalid code verifier",
|
||||
));
|
||||
}
|
||||
} else if q.code_verifier.is_some() {
|
||||
return Ok(error_response(&query, "invalid_grant", "Unexpected `code_verifier` parameter!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_grant",
|
||||
"Unexpected `code_verifier` parameter!",
|
||||
));
|
||||
}
|
||||
|
||||
if session.access_token.is_some() {
|
||||
return Ok(error_response(&query, "invalid_request", "Authorization code already used!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Authorization code already used!",
|
||||
));
|
||||
}
|
||||
|
||||
session.regenerate_access_and_refresh_tokens(&app_config, &jwt_signer)?;
|
||||
|
||||
sessions.send(openid_sessions_actor::UpdateSession(session.clone()))
|
||||
.await.unwrap();
|
||||
sessions
|
||||
.send(openid_sessions_actor::UpdateSession(session.clone()))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let user: Option<User> = users.send(users_actor::GetUserRequest(session.user.clone()))
|
||||
.await.unwrap().0;
|
||||
let user: Option<User> = users
|
||||
.send(users_actor::GetUserRequest(session.user.clone()))
|
||||
.await
|
||||
.unwrap()
|
||||
.0;
|
||||
let user = match user {
|
||||
None => return Ok(error_response(&query, "invalid_request", "User not found!")),
|
||||
Some(u) => u,
|
||||
@ -359,28 +456,44 @@ pub async fn token(req: HttpRequest,
|
||||
|
||||
("refresh_token", _, Some(q)) => {
|
||||
let mut session: Session = match sessions
|
||||
.send(openid_sessions_actor::FindSessionByRefreshToken(q.refresh_token.clone()))
|
||||
.await.unwrap()
|
||||
.send(openid_sessions_actor::FindSessionByRefreshToken(
|
||||
q.refresh_token.clone(),
|
||||
))
|
||||
.await
|
||||
.unwrap()
|
||||
{
|
||||
None => {
|
||||
return Ok(error_response(&query, "invalid_request", "Session not found!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Session not found!",
|
||||
));
|
||||
}
|
||||
Some(s) => s,
|
||||
};
|
||||
|
||||
if session.client != client.id {
|
||||
return Ok(error_response(&query, "invalid_request", "Client mismatch!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Client mismatch!",
|
||||
));
|
||||
}
|
||||
|
||||
if session.refresh_token_expire_at < time() {
|
||||
return Ok(error_response(&query, "access_denied", "Refresh token has expired!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"access_denied",
|
||||
"Refresh token has expired!",
|
||||
));
|
||||
}
|
||||
|
||||
session.regenerate_access_and_refresh_tokens(&app_config, &jwt_signer)?;
|
||||
|
||||
sessions
|
||||
.send(openid_sessions_actor::UpdateSession(session.clone()))
|
||||
.await.unwrap();
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
TokenResponse {
|
||||
access_token: session.access_token.expect("Missing access token!"),
|
||||
@ -392,7 +505,11 @@ pub async fn token(req: HttpRequest,
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Ok(error_response(&query, "invalid_request", "Grant type unsupported!"));
|
||||
return Ok(error_response(
|
||||
&query,
|
||||
"invalid_request",
|
||||
"Grant type unsupported!",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -408,16 +525,20 @@ struct CertsResponse {
|
||||
}
|
||||
|
||||
pub async fn cert_uri(jwt_signer: web::Data<JWTSigner>) -> impl Responder {
|
||||
HttpResponse::Ok().json(CertsResponse { keys: vec![jwt_signer.get_json_web_key()] })
|
||||
HttpResponse::Ok().json(CertsResponse {
|
||||
keys: vec![jwt_signer.get_json_web_key()],
|
||||
})
|
||||
}
|
||||
|
||||
fn user_info_error(err: &str, description: &str) -> HttpResponse {
|
||||
HttpResponse::Unauthorized()
|
||||
.insert_header(("WWW-Authenticate", format!(
|
||||
"Bearer error=\"{}\", error_description=\"{}\"",
|
||||
err,
|
||||
description
|
||||
)))
|
||||
.insert_header((
|
||||
"WWW-Authenticate",
|
||||
format!(
|
||||
"Bearer error=\"{}\", error_description=\"{}\"",
|
||||
err, description
|
||||
),
|
||||
))
|
||||
.finish()
|
||||
}
|
||||
|
||||
@ -426,37 +547,46 @@ pub struct UserInfoQuery {
|
||||
access_token: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn user_info_post(req: HttpRequest,
|
||||
form: Option<web::Form<UserInfoQuery>>,
|
||||
query: web::Query<UserInfoQuery>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>) -> impl Responder {
|
||||
user_info(req,
|
||||
form
|
||||
.map(|f| f.0.access_token)
|
||||
.unwrap_or_default()
|
||||
.or(query.0.access_token),
|
||||
sessions,
|
||||
users,
|
||||
).await
|
||||
pub async fn user_info_post(
|
||||
req: HttpRequest,
|
||||
form: Option<web::Form<UserInfoQuery>>,
|
||||
query: web::Query<UserInfoQuery>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>,
|
||||
) -> impl Responder {
|
||||
user_info(
|
||||
req,
|
||||
form.map(|f| f.0.access_token)
|
||||
.unwrap_or_default()
|
||||
.or(query.0.access_token),
|
||||
sessions,
|
||||
users,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn user_info_get(req: HttpRequest, query: web::Query<UserInfoQuery>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>) -> impl Responder {
|
||||
pub async fn user_info_get(
|
||||
req: HttpRequest,
|
||||
query: web::Query<UserInfoQuery>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>,
|
||||
) -> impl Responder {
|
||||
user_info(req, query.0.access_token, sessions, users).await
|
||||
}
|
||||
|
||||
/// Authenticate request using RFC6750 <https://datatracker.ietf.org/doc/html/rfc6750>///
|
||||
async fn user_info(req: HttpRequest, token: Option<String>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>) -> impl Responder {
|
||||
async fn user_info(
|
||||
req: HttpRequest,
|
||||
token: Option<String>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
users: web::Data<Addr<UsersActor>>,
|
||||
) -> impl Responder {
|
||||
let token = match token {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
let token = match req.headers().get("Authorization") {
|
||||
None => return user_info_error("invalid_request", "Missing access token!"),
|
||||
Some(t) => t
|
||||
Some(t) => t,
|
||||
};
|
||||
|
||||
let token = match token.to_str() {
|
||||
@ -465,7 +595,12 @@ async fn user_info(req: HttpRequest, token: Option<String>,
|
||||
};
|
||||
|
||||
let token = match token.strip_prefix("Bearer ") {
|
||||
None => return user_info_error("invalid_request", "Header token does not start with 'Bearer '!"),
|
||||
None => {
|
||||
return user_info_error(
|
||||
"invalid_request",
|
||||
"Header token does not start with 'Bearer '!",
|
||||
)
|
||||
}
|
||||
Some(t) => t,
|
||||
};
|
||||
|
||||
@ -474,7 +609,9 @@ async fn user_info(req: HttpRequest, token: Option<String>,
|
||||
};
|
||||
|
||||
let session: Option<Session> = sessions
|
||||
.send(openid_sessions_actor::FindSessionByAccessToken(token)).await.unwrap();
|
||||
.send(openid_sessions_actor::FindSessionByAccessToken(token))
|
||||
.await
|
||||
.unwrap();
|
||||
let session = match session {
|
||||
None => {
|
||||
return user_info_error("invalid_request", "Session not found!");
|
||||
@ -486,7 +623,11 @@ async fn user_info(req: HttpRequest, token: Option<String>,
|
||||
return user_info_error("invalid_request", "Access token has expired!");
|
||||
}
|
||||
|
||||
let user: Option<User> = users.send(users_actor::GetUserRequest(session.user)).await.unwrap().0;
|
||||
let user: Option<User> = users
|
||||
.send(users_actor::GetUserRequest(session.user))
|
||||
.await
|
||||
.unwrap()
|
||||
.0;
|
||||
let user = match user {
|
||||
None => {
|
||||
return user_info_error("invalid_request", "Failed to extract user information!");
|
||||
@ -494,14 +635,13 @@ async fn user_info(req: HttpRequest, token: Option<String>,
|
||||
Some(u) => u,
|
||||
};
|
||||
|
||||
HttpResponse::Ok()
|
||||
.json(OpenIDUserInfo {
|
||||
name: user.full_name(),
|
||||
sub: user.uid.0,
|
||||
given_name: user.first_name,
|
||||
family_name: user.last_name,
|
||||
preferred_username: user.username,
|
||||
email: user.email,
|
||||
email_verified: true,
|
||||
})
|
||||
}
|
||||
HttpResponse::Ok().json(OpenIDUserInfo {
|
||||
name: user.full_name(),
|
||||
sub: user.uid.0,
|
||||
given_name: user.first_name,
|
||||
family_name: user.last_name,
|
||||
preferred_username: user.username,
|
||||
email: user.email,
|
||||
email_verified: true,
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user