Skip to content

Commit

Permalink
Merge branch 'dev' into groups-ui
Browse files Browse the repository at this point in the history
  • Loading branch information
filipslezaklab authored Jan 29, 2024
2 parents 61e956c + 62f5652 commit f7469e9
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 15 deletions.
65 changes: 50 additions & 15 deletions src/handlers/openid_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ use chrono::Utc;
use openidconnect::{
core::{
CoreAuthErrorResponseType, CoreClaimName, CoreErrorResponseType, CoreGenderClaim,
CoreGrantType, CoreHmacKey, CoreIdToken, CoreIdTokenClaims, CoreIdTokenFields,
CoreJsonWebKeySet, CoreJwsSigningAlgorithm, CoreProviderMetadata, CoreResponseType,
CoreRsaPrivateSigningKey, CoreSubjectIdentifierType, CoreTokenResponse, CoreTokenType,
CoreGrantType, CoreHmacKey, CoreJsonWebKeySet, CoreJsonWebKeyType,
CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreProviderMetadata,
CoreResponseType, CoreRsaPrivateSigningKey, CoreSubjectIdentifierType, CoreTokenType,
},
url::Url,
AccessToken, Audience, AuthUrl, AuthorizationCode, EmptyAdditionalClaims,
AccessToken, AdditionalClaims, Audience, AuthUrl, AuthorizationCode,
EmptyAdditionalProviderMetadata, EmptyExtraTokenFields, EndUserEmail, EndUserFamilyName,
EndUserGivenName, EndUserName, EndUserPhoneNumber, EndUserUsername, IssuerUrl,
JsonWebKeySetUrl, LocalizedClaim, Nonce, PkceCodeChallenge, PkceCodeVerifier,
PrivateSigningKey, RefreshToken, ResponseTypes, Scope, StandardClaims, StandardErrorResponse,
StandardTokenResponse, SubjectIdentifier, TokenUrl, UserInfoUrl,
EndUserGivenName, EndUserName, EndUserPhoneNumber, EndUserUsername, IdToken, IdTokenClaims,
IdTokenFields, IssuerUrl, JsonWebKeySetUrl, LocalizedClaim, Nonce, PkceCodeChallenge,
PkceCodeVerifier, PrivateSigningKey, RefreshToken, ResponseTypes, Scope, StandardClaims,
StandardErrorResponse, StandardTokenResponse, SubjectIdentifier, TokenUrl, UserInfoUrl,
};
use serde::{
de::{Deserialize, Deserializer, Error as DeError, Unexpected, Visitor},
Expand Down Expand Up @@ -83,6 +83,16 @@ pub async fn discovery_keys(State(appstate): State<AppState>) -> ApiResult {
status: StatusCode::OK,
})
}
pub type DefguardIdTokenFields = IdTokenFields<
GroupClaims,
EmptyExtraTokenFields,
CoreGenderClaim,
CoreJweContentEncryptionAlgorithm,
CoreJwsSigningAlgorithm,
CoreJsonWebKeyType,
>;

pub type DefguardTokenResponse = StandardTokenResponse<DefguardIdTokenFields, CoreTokenType>;

/// Provide `OAuth2Client` when Basic Authorization header contains `client_id` and `client_secret`.
#[async_trait]
Expand Down Expand Up @@ -474,6 +484,21 @@ pub async fn authorization(
Ok(redirect_to(url, private_cookies))
}

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, Default)]
pub struct GroupClaims {
#[serde(skip_serializing_if = "Option::is_none")]
groups: Option<Vec<String>>,
}

impl AdditionalClaims for GroupClaims {}

pub async fn get_group_claims(pool: &DbPool, user: &User) -> Result<GroupClaims, WebError> {
let groups = user.member_of_names(pool).await?;
Ok(GroupClaims {
groups: Some(groups),
})
}

/// Login Authorization Endpoint redirect with authorization code
pub async fn secure_authorization(
session_info: SessionInfo,
Expand Down Expand Up @@ -601,7 +626,8 @@ impl TokenRequest {
base_url: &Url,
secret: T,
rsa_key: Option<CoreRsaPrivateSigningKey>,
) -> Result<CoreTokenResponse, CoreErrorResponseType>
group_claims: GroupClaims,
) -> Result<DefguardTokenResponse, CoreErrorResponseType>
where
T: Into<Vec<u8>>,
{
Expand Down Expand Up @@ -631,24 +657,25 @@ impl TokenRequest {
let authorization_code = AuthorizationCode::new(code.into());
let issue_time = Utc::now();
let expiration = issue_time + chrono::Duration::seconds(SESSION_TIMEOUT as i64);
let id_token_claims = CoreIdTokenClaims::new(
let id_token_claims = IdTokenClaims::new(
IssuerUrl::from_url(base_url.clone()),
vec![Audience::new(auth_code.client_id.clone())],
expiration,
issue_time,
claims,
EmptyAdditionalClaims {},
group_claims,
)
.set_nonce(auth_code.nonce.clone().map(Nonce::new));

let id_token = match rsa_key {
Some(key) => CoreIdToken::new(
Some(key) => IdToken::new(
id_token_claims,
&key,
CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256,
Some(&access_token),
Some(&authorization_code),
),
None => CoreIdToken::new(
None => IdToken::new(
id_token_claims,
&CoreHmacKey::new(secret),
CoreJwsSigningAlgorithm::HmacSha256,
Expand All @@ -661,10 +688,10 @@ impl TokenRequest {
None
};

let mut token_response = CoreTokenResponse::new(
let mut token_response = DefguardTokenResponse::new(
access_token,
CoreTokenType::Bearer,
CoreIdTokenFields::new(id_token, EmptyExtraTokenFields {}),
IdTokenFields::new(id_token, EmptyExtraTokenFields {}),
);
token_response.set_refresh_token(Some(RefreshToken::new(token.refresh_token.clone())));
Ok(token_response)
Expand Down Expand Up @@ -767,13 +794,19 @@ pub async fn token(
auth_code.redirect_uri.clone(),
auth_code.scope.clone(),
);
let group_claims = if auth_code.scope.contains("groups") {
get_group_claims(&appstate.pool, &user).await?
} else {
GroupClaims { groups: None }
};
match form.authorization_code_flow(
&auth_code,
&token,
(&user).into(),
&appstate.config.url,
client.client_secret,
appstate.config.openid_key(),
group_claims,
) {
Ok(response) => {
token.save(&appstate.pool).await?;
Expand Down Expand Up @@ -879,6 +912,7 @@ pub async fn openid_configuration(State(appstate): State<AppState>) -> ApiResult
Scope::new("profile".into()),
Scope::new("email".into()),
Scope::new("phone".into()),
Scope::new("groups".into()),
]))
.set_claims_supported(Some(vec![
CoreClaimName::new("iss".into()),
Expand All @@ -891,6 +925,7 @@ pub async fn openid_configuration(State(appstate): State<AppState>) -> ApiResult
CoreClaimName::new("family_name".into()),
CoreClaimName::new("email".into()),
CoreClaimName::new("phone_number".into()),
CoreClaimName::new("groups".into()),
]))
.set_grant_types_supported(Some(vec![
CoreGrantType::AuthorizationCode,
Expand Down
4 changes: 4 additions & 0 deletions web/src/i18n/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,9 @@ const en: BaseTranslation = {
phone: {
label: 'Phone',
},
groups: {
label: 'Groups',
},
},
controls: {
addUrl: 'Add URL',
Expand Down Expand Up @@ -1182,6 +1185,7 @@ const en: BaseTranslation = {
profile: 'Know basic information from your profile like name, profile picture etc.',
email: 'Know your email address.',
phone: 'Know your phone number.',
groups: 'Know your groups membership.',
},
controls: {
accept: 'Accept',
Expand Down
20 changes: 20 additions & 0 deletions web/src/i18n/i18n-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,12 @@ type RootTranslation = {
*/
label: string
}
groups: {
/**
* G​r​o​u​p​s
*/
label: string
}
}
controls: {
/**
Expand Down Expand Up @@ -2761,6 +2767,10 @@ type RootTranslation = {
* K​n​o​w​ ​y​o​u​r​ ​p​h​o​n​e​ ​n​u​m​b​e​r​.
*/
phone: string
/**
* K​n​o​w​ ​y​o​u​r​ ​g​r​o​u​p​s​ ​m​e​m​b​e​r​s​h​i​p​.
*/
groups: string
}
controls: {
/**
Expand Down Expand Up @@ -6057,6 +6067,12 @@ export type TranslationFunctions = {
*/
label: () => LocalizedString
}
groups: {
/**
* Groups
*/
label: () => LocalizedString
}
}
controls: {
/**
Expand Down Expand Up @@ -6294,6 +6310,10 @@ export type TranslationFunctions = {
* Know your phone number.
*/
phone: () => LocalizedString
/**
* Know your groups membership.
*/
groups: () => LocalizedString
}
controls: {
/**
Expand Down
4 changes: 4 additions & 0 deletions web/src/i18n/pl/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,9 @@ Uwaga, konfiguracje tutaj podane, nie posiadają twojego klucza prywatnego. Musi
phone: {
label: 'Telefon',
},
groups: {
label: 'Grupy',
},
},
controls: {
addUrl: 'Dodaj URL',
Expand Down Expand Up @@ -1167,6 +1170,7 @@ Uwaga, konfiguracje tutaj podane, nie posiadają twojego klucza prywatnego. Musi
'Poznać podstawowe informacje z twojego profilu, takie jak login, imię itp',
email: 'Poznać twój adres e-mail.',
phone: 'Poznać twój numer telefonu.',
groups: 'Poznać twoje grupy.',
},
controls: {
accept: 'Akceptuj',
Expand Down
1 change: 1 addition & 0 deletions web/src/pages/allow/OpenidAllowPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const OpenidAllowPage = () => {
profile: LL.openidAllow.scopes.profile(),
email: LL.openidAllow.scopes.email(),
phone: LL.openidAllow.scopes.phone(),
groups: LL.openidAllow.scopes.groups(),
};

if (loadingInfo) return <LoaderPage />;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ export const OpenIdClientModalFormScopes = ({ control, disabled = false }: Props
value={value.includes(OpenIdClientScope.PHONE)}
onChange={() => handleChange(OpenIdClientScope.PHONE, value)}
/>
<LabeledCheckbox
data-testid="field-scope-groups"
label={LL.openidOverview.modals.openidClientModal.form.fields.groups.label()}
disabled={disabled}
value={value.includes(OpenIdClientScope.GROUPS)}
onChange={() => handleChange(OpenIdClientScope.GROUPS, value)}
/>
</div>
);
};
1 change: 1 addition & 0 deletions web/src/pages/openid/modals/OpenIdClientModal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export enum OpenIdClientScope {
PROFILE = 'profile',
EMAIL = 'email',
PHONE = 'phone',
GROUPS = 'groups',
}

0 comments on commit f7469e9

Please sign in to comment.