Emit id_token
This commit is contained in:
@ -1,16 +1,20 @@
|
||||
use actix::Addr;
|
||||
use actix_identity::Identity;
|
||||
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::{OpenIDSessionsActor, Session, SessionID};
|
||||
use crate::constants::{AUTHORIZE_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};
|
||||
use crate::controllers::base_controller::FatalErrorPage;
|
||||
use crate::data::app_config::AppConfig;
|
||||
use crate::data::client::{ClientID, ClientManager};
|
||||
use crate::data::current_user::CurrentUser;
|
||||
use crate::data::id_token::IdToken;
|
||||
use crate::data::jwt_signer::{JsonWebKey, JWTSigner};
|
||||
use crate::data::openid_config::OpenIDConfig;
|
||||
use crate::data::session_identity::SessionIdentity;
|
||||
use crate::utils::string_utils::rand_str;
|
||||
use crate::utils::time::time;
|
||||
|
||||
@ -20,7 +24,7 @@ pub async fn get_configuration(app_conf: web::Data<AppConfig>) -> impl Responder
|
||||
authorization_endpoint: app_conf.full_url(AUTHORIZE_URI),
|
||||
token_endpoint: app_conf.full_url(TOKEN_URI),
|
||||
userinfo_endpoint: app_conf.full_url("openid/userinfo"),
|
||||
jwks_uri: app_conf.full_url("openid/jwks_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"],
|
||||
subject_types_supported: vec!["public"],
|
||||
@ -41,7 +45,7 @@ pub struct AuthorizeQuery {
|
||||
/// REQUIRED. OAuth 2.0 Client Identifier valid at the Authorization Server.
|
||||
client_id: ClientID,
|
||||
|
||||
/// REQUIRED. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of [RFC3986] (Simple String Comparison). When using this flow, the Redirection URI SHOULD use the https scheme; however, it MAY use the http scheme, provided that the Client Type is confidential, as defined in Section 2.1 of OAuth 2.0, and provided the OP allows the use of http Redirection URIs in this case. The Redirection URI MAY use an alternate scheme, such as one that is intended to identify a callback into a native application.
|
||||
/// REQUIRED. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of RFC3986 (Simple String Comparison). When using this flow, the Redirection URI SHOULD use the https scheme; however, it MAY use the http scheme, provided that the Client Type is confidential, as defined in Section 2.1 of OAuth 2.0, and provided the OP allows the use of http Redirection URIs in this case. The Redirection URI MAY use an alternate scheme, such as one that is intended to identify a callback into a native application.
|
||||
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.
|
||||
@ -50,7 +54,7 @@ pub struct AuthorizeQuery {
|
||||
/// 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>,
|
||||
|
||||
/// OPTIONAL - https://ldapwiki.com/wiki/Code_challenge_method
|
||||
/// OPTIONAL - <https://ldapwiki.com/wiki/Code_challenge_method>
|
||||
code_challenge: Option<String>,
|
||||
code_challenge_method: Option<String>,
|
||||
}
|
||||
@ -70,7 +74,7 @@ fn error_redirect(query: &AuthorizeQuery, error: &str, description: &str) -> Htt
|
||||
.finish()
|
||||
}
|
||||
|
||||
pub async fn authorize(user: CurrentUser, query: web::Query<AuthorizeQuery>,
|
||||
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) {
|
||||
@ -123,6 +127,7 @@ pub async fn authorize(user: CurrentUser, query: web::Query<AuthorizeQuery>,
|
||||
session_id: SessionID(rand_str(OPEN_ID_SESSION_LEN)),
|
||||
client: client.id,
|
||||
user: user.uid.clone(),
|
||||
auth_time: SessionIdentity(&id).auth_time(),
|
||||
redirect_uri,
|
||||
authorization_code: rand_str(OPEN_ID_AUTHORIZATION_CODE_LEN),
|
||||
authorization_code_expire_at: time() + OPEN_ID_AUTHORIZATION_CODE_TIMEOUT,
|
||||
@ -168,7 +173,11 @@ pub struct TokenResponse {
|
||||
pub async fn token(req: HttpRequest,
|
||||
query: web::Form<TokenQuery>,
|
||||
clients: web::Data<ClientManager>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>) -> actix_web::Result<HttpResponse> {
|
||||
app_config: web::Data<AppConfig>,
|
||||
sessions: web::Data<Addr<OpenIDSessionsActor>>,
|
||||
jwt_signer: web::Data<JWTSigner>) -> actix_web::Result<HttpResponse> {
|
||||
// TODO : add refresh tokens : https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens
|
||||
// TODO : check auth challenge
|
||||
|
||||
// Extraction authentication information
|
||||
let authorization_header = req.headers().get("authorization");
|
||||
@ -258,6 +267,17 @@ pub async fn token(req: HttpRequest,
|
||||
.await.unwrap();
|
||||
|
||||
|
||||
// Generate id token
|
||||
let token = IdToken {
|
||||
issuer: app_config.website_origin.to_string(),
|
||||
subject_identifier: session.user,
|
||||
audience: session.client.0.to_string(),
|
||||
expiration_time: session.access_token_expire_at,
|
||||
issued_at: time(),
|
||||
auth_time: session.auth_time,
|
||||
nonce: session.nonce,
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.append_header(("Cache-Control", "no-store"))
|
||||
.append_header(("Pragam", "no-cache"))
|
||||
@ -266,6 +286,15 @@ pub async fn token(req: HttpRequest,
|
||||
token_type: "Bearer",
|
||||
refresh_token: session.refresh_token,
|
||||
expires_in: session.access_token_expire_at - time(),
|
||||
id_token: session.session_id.0,
|
||||
id_token: jwt_signer.sign_token(token.to_jwt_claims())?
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct CertsResponse {
|
||||
keys: Vec<JsonWebKey>,
|
||||
}
|
||||
|
||||
pub async fn cert_uri(jwt_signer: web::Data<JWTSigner>) -> impl Responder {
|
||||
HttpResponse::Ok().json(CertsResponse { keys: vec![jwt_signer.get_json_web_key()] })
|
||||
}
|
Reference in New Issue
Block a user