|
@ -91,16 +91,26 @@ fn _refresh_login(data: ConnectData, conn: DbConn) -> JsonResult { |
|
|
struct TokenPayload { |
|
|
struct TokenPayload { |
|
|
exp: i64, |
|
|
exp: i64, |
|
|
email: String, |
|
|
email: String, |
|
|
|
|
|
nonce: String, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fn _authorization_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult { |
|
|
fn _authorization_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult { |
|
|
let org_identifier = data.org_identifier.as_ref().unwrap(); |
|
|
let org_identifier = data.org_identifier.as_ref().unwrap(); |
|
|
let code = data.code.as_ref().unwrap(); |
|
|
let code = data.code.as_ref().unwrap(); |
|
|
let (access_token, refresh_token) = match get_auth_code_access_token(&code, &org_identifier, &conn) { |
|
|
let organization = Organization::find_by_identifier(org_identifier, &conn).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
let (access_token, refresh_token) = match get_auth_code_access_token(&code, &organization) { |
|
|
Ok((access_token, refresh_token)) => (access_token, refresh_token), |
|
|
Ok((access_token, refresh_token)) => (access_token, refresh_token), |
|
|
Err(err) => err!(err), |
|
|
Err(err) => err!(err), |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
let token = jsonwebtoken::dangerous_insecure_decode::<TokenPayload>(access_token.as_str()).unwrap().claims; |
|
|
let token = jsonwebtoken::dangerous_insecure_decode::<TokenPayload>(access_token.as_str()).unwrap().claims; |
|
|
|
|
|
let nonce = token.nonce; |
|
|
|
|
|
|
|
|
|
|
|
match SsoNonce::find_by_org_and_nonce(&organization.uuid, &nonce, &conn) { |
|
|
|
|
|
Some(sso_nonce) => { |
|
|
|
|
|
match sso_nonce.delete(&conn) { |
|
|
|
|
|
Ok(_) => { |
|
|
let expiry = token.exp; |
|
|
let expiry = token.exp; |
|
|
let user_email = token.email; |
|
|
let user_email = token.email; |
|
|
let now = Local::now(); |
|
|
let now = Local::now(); |
|
@ -145,6 +155,14 @@ fn _authorization_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonR |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Ok(Json(result)) |
|
|
Ok(Json(result)) |
|
|
|
|
|
}, |
|
|
|
|
|
Err(_) => err!("Failed to delete nonce"), |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
None => { |
|
|
|
|
|
err!("Invalid nonce") |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult { |
|
|
fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult { |
|
@ -558,15 +576,11 @@ use openidconnect::{ |
|
|
Scope, OAuth2TokenResponse, |
|
|
Scope, OAuth2TokenResponse, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
fn get_client_from_identifier (identifier: &str, conn: &DbConn) -> Result<CoreClient, &'static str> { |
|
|
fn get_client_from_org (organization: &Organization) -> Result<CoreClient, &'static str> { |
|
|
let organization = Organization::find_by_identifier(identifier, conn); |
|
|
|
|
|
|
|
|
|
|
|
match organization { |
|
|
|
|
|
Some(organization) => { |
|
|
|
|
|
let redirect = organization.callback_path.to_string(); |
|
|
let redirect = organization.callback_path.to_string(); |
|
|
let client_id = ClientId::new(organization.client_id.unwrap_or_default()); |
|
|
let client_id = ClientId::new(organization.client_id.as_ref().unwrap().to_string()); |
|
|
let client_secret = ClientSecret::new(organization.client_secret.unwrap_or_default()); |
|
|
let client_secret = ClientSecret::new(organization.client_secret.as_ref().unwrap().to_string()); |
|
|
let issuer_url = IssuerUrl::new(organization.authority.unwrap_or_default()).expect("invalid issuer URL"); |
|
|
let issuer_url = IssuerUrl::new(organization.authority.as_ref().unwrap().to_string()).expect("invalid issuer URL"); |
|
|
let provider_metadata = match CoreProviderMetadata::discover(&issuer_url, http_client) { |
|
|
let provider_metadata = match CoreProviderMetadata::discover(&issuer_url, http_client) { |
|
|
Ok(metadata) => metadata, |
|
|
Ok(metadata) => metadata, |
|
|
Err(_err) => { |
|
|
Err(_err) => { |
|
@ -580,11 +594,6 @@ fn get_client_from_identifier (identifier: &str, conn: &DbConn) -> Result<CoreCl |
|
|
) |
|
|
) |
|
|
.set_redirect_uri(RedirectUrl::new(redirect).expect("Invalid redirect URL")); |
|
|
.set_redirect_uri(RedirectUrl::new(redirect).expect("Invalid redirect URL")); |
|
|
return Ok(client); |
|
|
return Ok(client); |
|
|
}, |
|
|
|
|
|
None => { |
|
|
|
|
|
Err("unable to find org") |
|
|
|
|
|
}, |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[get("/connect/authorize?<domain_hint>&<state>")] |
|
|
#[get("/connect/authorize?<domain_hint>&<state>")] |
|
@ -593,11 +602,10 @@ fn authorize( |
|
|
state: String, |
|
|
state: String, |
|
|
conn: DbConn, |
|
|
conn: DbConn, |
|
|
) -> ApiResult<Redirect> { |
|
|
) -> ApiResult<Redirect> { |
|
|
match get_client_from_identifier(&domain_hint, &conn) { |
|
|
let organization = Organization::find_by_identifier(&domain_hint, &conn).unwrap(); |
|
|
|
|
|
match get_client_from_org(&organization) { |
|
|
Ok(client) => { |
|
|
Ok(client) => { |
|
|
// TODO store the nonce for validation on authorization token exchange - unclear where to store
|
|
|
let (mut authorize_url, _csrf_state, nonce) = client |
|
|
// this
|
|
|
|
|
|
let (mut authorize_url, _csrf_state, _nonce) = client |
|
|
|
|
|
.authorize_url( |
|
|
.authorize_url( |
|
|
AuthenticationFlow::<CoreResponseType>::AuthorizationCode, |
|
|
AuthenticationFlow::<CoreResponseType>::AuthorizationCode, |
|
|
CsrfToken::new_random, |
|
|
CsrfToken::new_random, |
|
@ -607,6 +615,9 @@ fn authorize( |
|
|
.add_scope(Scope::new("profile".to_string())) |
|
|
.add_scope(Scope::new("profile".to_string())) |
|
|
.url(); |
|
|
.url(); |
|
|
|
|
|
|
|
|
|
|
|
let sso_nonce = SsoNonce::new(organization.uuid, nonce.secret().to_string()); |
|
|
|
|
|
sso_nonce.save(&conn)?; |
|
|
|
|
|
|
|
|
// it seems impossible to set the state going in dynamically (requires static lifetime string)
|
|
|
// it seems impossible to set the state going in dynamically (requires static lifetime string)
|
|
|
// so I change it after the fact
|
|
|
// so I change it after the fact
|
|
|
let old_pairs = authorize_url.query_pairs().clone(); |
|
|
let old_pairs = authorize_url.query_pairs().clone(); |
|
@ -628,12 +639,10 @@ fn authorize( |
|
|
|
|
|
|
|
|
fn get_auth_code_access_token ( |
|
|
fn get_auth_code_access_token ( |
|
|
code: &str, |
|
|
code: &str, |
|
|
org_identifier: &str, |
|
|
organization: &Organization, |
|
|
conn: &DbConn, |
|
|
|
|
|
) -> Result<(String, String), &'static str> { |
|
|
) -> Result<(String, String), &'static str> { |
|
|
let oidc_code = AuthorizationCode::new(String::from(code)); |
|
|
let oidc_code = AuthorizationCode::new(String::from(code)); |
|
|
|
|
|
match get_client_from_org(organization) { |
|
|
match get_client_from_identifier(org_identifier, conn) { |
|
|
|
|
|
Ok(client) => { |
|
|
Ok(client) => { |
|
|
match client.exchange_code(oidc_code).request(http_client) { |
|
|
match client.exchange_code(oidc_code).request(http_client) { |
|
|
Ok(token_response) => { |
|
|
Ok(token_response) => { |
|
|