Start to build userinfo endpoint
This commit is contained in:
parent
27cee8d3a0
commit
b867016a71
@ -46,6 +46,7 @@ pub const TEMPORARY_PASSWORDS_LEN: usize = 20;
|
||||
pub const AUTHORIZE_URI: &str = "/openid/authorize";
|
||||
pub const TOKEN_URI: &str = "/openid/token";
|
||||
pub const CERT_URI: &str = "/openid/jwks_uri";
|
||||
pub const USERINFO_URI: &str = "/openid/userinfo";
|
||||
|
||||
/// Open ID constants
|
||||
pub const OPEN_ID_SESSION_CLEANUP_INTERVAL: Duration = Duration::from_secs(60);
|
||||
|
@ -8,7 +8,7 @@ use askama::Template;
|
||||
|
||||
use crate::actors::openid_sessions_actor;
|
||||
use crate::actors::openid_sessions_actor::{OpenIDSessionsActor, Session, SessionID};
|
||||
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};
|
||||
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;
|
||||
use crate::data::client::{ClientID, ClientManager};
|
||||
@ -26,7 +26,7 @@ pub async fn get_configuration(app_conf: web::Data<AppConfig>) -> impl Responder
|
||||
issuer: app_conf.full_url("/"),
|
||||
authorization_endpoint: app_conf.full_url(AUTHORIZE_URI),
|
||||
token_endpoint: app_conf.full_url(TOKEN_URI),
|
||||
userinfo_endpoint: app_conf.full_url("openid/userinfo"),
|
||||
userinfo_endpoint: app_conf.full_url(USERINFO_URI),
|
||||
jwks_uri: app_conf.full_url(CERT_URI),
|
||||
scopes_supported: vec!["openid", "profile", "email"],
|
||||
response_types_supported: vec!["code", "id_token", "token id_token"],
|
||||
@ -388,3 +388,61 @@ 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()] })
|
||||
}
|
||||
|
||||
fn user_info_error(err: &str, description: &str) -> HttpResponse {
|
||||
HttpResponse::Unauthorized()
|
||||
.insert_header(("WWW-Authenticate", format!(
|
||||
"Bearer error=\"{}\", error_description=\"{}\"",
|
||||
err,
|
||||
description
|
||||
)))
|
||||
.finish()
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct UserInfoQuery {
|
||||
access_token: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn user_info_post(req: HttpRequest,
|
||||
form: Option<web::Form<UserInfoQuery>>,
|
||||
query: web::Query<UserInfoQuery>) -> impl Responder {
|
||||
user_info(req,
|
||||
form
|
||||
.map(|f| f.0.access_token)
|
||||
.unwrap_or_default()
|
||||
.or(query.0.access_token),
|
||||
).await
|
||||
}
|
||||
|
||||
pub async fn user_info_get(req: HttpRequest, query: web::Query<UserInfoQuery>) -> impl Responder {
|
||||
user_info(req, query.0.access_token).await
|
||||
}
|
||||
|
||||
/// Authenticate request using RFC6750 <https://datatracker.ietf.org/doc/html/rfc6750>///
|
||||
async fn user_info(req: HttpRequest, token: Option<String>) -> 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
|
||||
};
|
||||
|
||||
let token = match token.to_str() {
|
||||
Err(_) => return user_info_error("invalid_request", "Failed to decode token!"),
|
||||
Ok(t) => t,
|
||||
};
|
||||
|
||||
let token = match token.strip_prefix("Bearer ") {
|
||||
None => return user_info_error("invalid_request", "Header token does not start with 'Bearer '!"),
|
||||
Some(t) => t,
|
||||
};
|
||||
|
||||
token.to_string()
|
||||
}
|
||||
};
|
||||
|
||||
// TODO : continue <https://openid.net/specs/openid-connect-core-1_0.html#RFC6749>
|
||||
HttpResponse::Ok().body(format!("token is {}", token))
|
||||
}
|
@ -136,6 +136,8 @@ async fn main() -> std::io::Result<()> {
|
||||
.route(AUTHORIZE_URI, web::get().to(openid_controller::authorize))
|
||||
.route(TOKEN_URI, web::post().to(openid_controller::token))
|
||||
.route(CERT_URI, web::get().to(openid_controller::cert_uri))
|
||||
.route(USERINFO_URI, web::post().to(openid_controller::user_info_post))
|
||||
.route(USERINFO_URI, web::get().to(openid_controller::user_info_get))
|
||||
})
|
||||
.bind(listen_address)?
|
||||
.run()
|
||||
|
@ -13,7 +13,7 @@ use actix_web::body::EitherBody;
|
||||
use actix_web::http::{header, Method};
|
||||
use askama::Template;
|
||||
|
||||
use crate::constants::{ADMIN_ROUTES, AUTHENTICATED_ROUTES, AUTHORIZE_URI, TOKEN_URI};
|
||||
use crate::constants::{ADMIN_ROUTES, AUTHENTICATED_ROUTES, AUTHORIZE_URI, TOKEN_URI, USERINFO_URI};
|
||||
use crate::controllers::base_controller::{FatalErrorPage, redirect_user_for_login};
|
||||
use crate::data::app_config::AppConfig;
|
||||
use crate::data::session_identity::{SessionIdentity, SessionIdentityData, SessionStatus};
|
||||
@ -91,7 +91,7 @@ impl<S, B> Service<ServiceRequest> for AuthInnerMiddleware<S>
|
||||
|
||||
// Check if POST request comes from another website (block invalid origins)
|
||||
let origin = req.headers().get(header::ORIGIN);
|
||||
if req.method() == Method::POST && req.path() != TOKEN_URI {
|
||||
if req.method() == Method::POST && req.path() != TOKEN_URI && req.path() != USERINFO_URI {
|
||||
if let Some(o) = origin {
|
||||
if !o.to_str().unwrap_or("bad").eq(&config.website_origin) {
|
||||
log::warn!(
|
||||
|
Loading…
Reference in New Issue
Block a user