Userinfo endpoint is working

This commit is contained in:
Pierre HUBERT 2022-04-15 17:04:23 +02:00
parent b867016a71
commit 819210ae86
4 changed files with 88 additions and 8 deletions

View File

@ -50,6 +50,10 @@ pub struct FindSessionByAuthorizationCode(pub String);
#[rtype(result = "Option<Session>")]
pub struct FindSessionByRefreshToken(pub String);
#[derive(Message)]
#[rtype(result = "Option<Session>")]
pub struct FindSessionByAccessToken(pub String);
#[derive(Message)]
#[rtype(result = "()")]
pub struct MarkAuthorizationCodeUsed(pub String);
@ -111,6 +115,17 @@ impl Handler<FindSessionByRefreshToken> for OpenIDSessionsActor {
}
}
impl Handler<FindSessionByAccessToken> for OpenIDSessionsActor {
type Result = Option<Session>;
fn handle(&mut self, msg: FindSessionByAccessToken, _ctx: &mut Self::Context) -> Self::Result {
self.session
.iter()
.find(|f| f.access_token.eq(&msg.0))
.cloned()
}
}
impl Handler<MarkAuthorizationCodeUsed> for OpenIDSessionsActor {
type Result = ();

View File

@ -6,8 +6,9 @@ use actix_web::{HttpRequest, HttpResponse, Responder, web};
use actix_web::error::ErrorUnauthorized;
use askama::Template;
use crate::actors::openid_sessions_actor;
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::constants::{AUTHORIZE_URI, CERT_URI, OPEN_ID_ACCESS_TOKEN_LEN, OPEN_ID_ACCESS_TOKEN_TIMEOUT, OPEN_ID_AUTHORIZATION_CODE_LEN, OPEN_ID_AUTHORIZATION_CODE_TIMEOUT, OPEN_ID_REFRESH_TOKEN_LEN, OPEN_ID_REFRESH_TOKEN_TIMEOUT, OPEN_ID_SESSION_LEN, TOKEN_URI, USERINFO_URI};
use crate::controllers::base_controller::FatalErrorPage;
use crate::data::app_config::AppConfig;
@ -16,8 +17,10 @@ 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::open_id_user_info::OpenIDUserInfo;
use crate::data::openid_config::OpenIDConfig;
use crate::data::session_identity::SessionIdentity;
use crate::data::user::User;
use crate::utils::string_utils::rand_str;
use crate::utils::time::time;
@ -406,21 +409,29 @@ pub struct UserInfoQuery {
pub async fn user_info_post(req: HttpRequest,
form: Option<web::Form<UserInfoQuery>>,
query: web::Query<UserInfoQuery>) -> impl Responder {
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>) -> impl Responder {
user_info(req, query.0.access_token).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 {
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>) -> 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 => {
@ -443,6 +454,35 @@ async fn user_info(req: HttpRequest, token: Option<String>) -> impl Responder {
}
};
// TODO : continue <https://openid.net/specs/openid-connect-core-1_0.html#RFC6749>
HttpResponse::Ok().body(format!("token is {}", token))
let session: Option<Session> = sessions
.send(openid_sessions_actor::FindSessionByAccessToken(token)).await.unwrap();
let session = match session {
None => {
return user_info_error("invalid_request", "Session not found!");
}
Some(s) => s,
};
if session.access_token_expire_at < time() {
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 = match user {
None => {
return user_info_error("invalid_request", "Failed to extract user information!");
}
Some(u) => u,
};
HttpResponse::Ok()
.json(OpenIDUserInfo {
name: user.full_name(),
sub: user.uid,
given_name: user.first_name,
family_name: user.last_name,
preferred_username: user.username,
email: user.email,
email_verified: true,
})
}

View File

@ -9,3 +9,4 @@ pub mod openid_config;
pub mod jwt_signer;
pub mod id_token;
pub mod code_challenge;
pub mod open_id_user_info;

View File

@ -0,0 +1,24 @@
/// Refer to <https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims> for more information
#[derive(Debug, serde::Serialize)]
pub struct OpenIDUserInfo {
/// Subject - Identifier for the End-User at the Issuer
pub sub: String,
/// End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences.
pub name: String,
/// Given name(s) or first name(s) of the End-User. Note that in some cultures, people can have multiple given names; all can be present, with the names being separated by space characters.
pub given_name: String,
/// Surname(s) or last name(s) of the End-User. Note that in some cultures, people can have multiple family names or no family name; all can be present, with the names being separated by space characters.
pub family_name: String,
/// Shorthand name by which the End-User wishes to be referred to at the RP, such as janedoe or j.doe. This value MAY be any valid JSON string including special characters such as @, /, or whitespace. The RP MUST NOT rely upon this value being unique, as discussed in
pub preferred_username: String,
/// End-User's preferred e-mail address. Its value MUST conform to the RFC 5322 RFC5322 addr-spec syntax. The RP MUST NOT rely upon this value being unique, as discussed in Section 5.7.
pub email: String,
/// True if the End-User's e-mail address has been verified; otherwise false. When this Claim Value is true, this means that the OP took affirmative steps to ensure that this e-mail address was controlled by the End-User at the time the verification was performed. The means by which an e-mail address is verified is context-specific, and dependent upon the trust framework or contractual agreements within which the parties are operating.
pub email_verified: bool,
}