fix: remove hard requirement of grant type auth code for device code apps + warnings for missing urls (#7429)

* fix: if device Code is selected Auth Code no longer a hard requirement

* fix: create device code app without auth code as grant type

* fix: don't show redirect uris in overview for devicecode app wizard

* feat: reload component when oidc app is updated

* fix: oidcapp is valid grantTypes cannot be empty

* fix: auth code not mandatory if refresh token and device code combined
This commit is contained in:
Miguel Cabrerizo 2024-02-29 16:28:06 +01:00 committed by GitHub
parent b0e3d3d912
commit dfd7cba3f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 26 additions and 10 deletions

View File

@ -307,7 +307,7 @@
</span> </span>
</div> </div>
<div class="row"> <div class="row" *ngIf="appType?.value?.createType === AppCreateType.OIDC && authMethod?.value !== 'DEVICECODE'">
<span class="left cnsl-secondary-text"> <span class="left cnsl-secondary-text">
{{ 'APP.OIDC.REDIRECT' | translate }} {{ 'APP.OIDC.REDIRECT' | translate }}
</span> </span>
@ -322,7 +322,7 @@
</span> </span>
</div> </div>
<div class="row"> <div class="row" *ngIf="appType?.value?.createType === AppCreateType.OIDC && authMethod?.value !== 'DEVICECODE'">
<span class="left cnsl-secondary-text"> <span class="left cnsl-secondary-text">
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }} {{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
</span> </span>

View File

@ -77,6 +77,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
public authMethods: RadioItemAuthType[] = []; public authMethods: RadioItemAuthType[] = [];
private subscription?: Subscription; private subscription?: Subscription;
public projectId: string = ''; public projectId: string = '';
public appId: string = '';
public app?: App.AsObject; public app?: App.AsObject;
public environmentMap$ = this.envSvc.env.pipe( public environmentMap$ = this.envSvc.env.pipe(
@ -252,6 +253,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
if (projectId && appId) { if (projectId && appId) {
this.projectId = projectId; this.projectId = projectId;
this.appId = appId;
this.getData(projectId, appId); this.getData(projectId, appId);
} }
} }
@ -639,6 +641,9 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.currentAuthMethod = this.authMethodFromPartialConfig(config); this.currentAuthMethod = this.authMethodFromPartialConfig(config);
} }
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
setTimeout(() => {
this.getData(this.projectId, this.appId);
}, 1000);
}) })
.catch((error) => { .catch((error) => {
this.toast.showError(error); this.toast.showError(error);

View File

@ -95,7 +95,7 @@ export const DEVICE_CODE_METHOD: RadioItemAuthType = {
prefix: 'DEVICECODE', prefix: 'DEVICECODE',
background: 'linear-gradient(40deg, rgb(56 189 248) 30%, rgb(14 165 233))', background: 'linear-gradient(40deg, rgb(56 189 248) 30%, rgb(14 165 233))',
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE, responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE], grantType: [OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE],
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC, authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
recommended: false, recommended: false,
}; };
@ -133,7 +133,7 @@ export function getPartialConfigFromAuthMethod(authMethod: string):
config = { config = {
oidc: { oidc: {
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE], responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE], grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE],
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE, authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
}, },
}; };

View File

@ -149,17 +149,22 @@ func (a *OIDCApp) OriginsValid() bool {
} }
func ContainsRequiredGrantTypes(responseTypes []OIDCResponseType, grantTypes []OIDCGrantType) bool { func ContainsRequiredGrantTypes(responseTypes []OIDCResponseType, grantTypes []OIDCGrantType) bool {
required := RequiredOIDCGrantTypes(responseTypes) required := RequiredOIDCGrantTypes(responseTypes, grantTypes)
return ContainsOIDCGrantTypes(required, grantTypes) return ContainsOIDCGrantTypes(required, grantTypes)
} }
func RequiredOIDCGrantTypes(responseTypes []OIDCResponseType) (grantTypes []OIDCGrantType) { func RequiredOIDCGrantTypes(responseTypes []OIDCResponseType, grantTypesSet []OIDCGrantType) (grantTypes []OIDCGrantType) {
var implicit bool var implicit bool
for _, r := range responseTypes { for _, r := range responseTypes {
switch r { switch r {
case OIDCResponseTypeCode: case OIDCResponseTypeCode:
grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode) // #5684 when "Device Code" is selected, "Authorization Code" is no longer a hard requirement
if !containsOIDCGrantType(grantTypesSet, OIDCGrantTypeDeviceCode) {
grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode)
} else {
grantTypes = append(grantTypes, OIDCGrantTypeDeviceCode)
}
case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken: case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken:
if !implicit { if !implicit {
implicit = true implicit = true
@ -172,7 +177,7 @@ func RequiredOIDCGrantTypes(responseTypes []OIDCResponseType) (grantTypes []OIDC
} }
func (a *OIDCApp) getRequiredGrantTypes() []OIDCGrantType { func (a *OIDCApp) getRequiredGrantTypes() []OIDCGrantType {
return RequiredOIDCGrantTypes(a.ResponseTypes) return RequiredOIDCGrantTypes(a.ResponseTypes, a.GrantTypes)
} }
func ContainsOIDCGrantTypes(shouldContain, list []OIDCGrantType) bool { func ContainsOIDCGrantTypes(shouldContain, list []OIDCGrantType) bool {
@ -222,14 +227,15 @@ func GetOIDCV1Compliance(appType OIDCApplicationType, grantTypes []OIDCGrantType
} }
func checkGrantTypesCombination(compliance *Compliance, grantTypes []OIDCGrantType) { func checkGrantTypesCombination(compliance *Compliance, grantTypes []OIDCGrantType) {
if containsOIDCGrantType(grantTypes, OIDCGrantTypeRefreshToken) && !containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) { if !containsOIDCGrantType(grantTypes, OIDCGrantTypeDeviceCode) && containsOIDCGrantType(grantTypes, OIDCGrantTypeRefreshToken) && !containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) {
compliance.NoneCompliant = true compliance.NoneCompliant = true
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.GrantType.Refresh.NoAuthCode") compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.GrantType.Refresh.NoAuthCode")
} }
} }
func checkRedirectURIs(compliance *Compliance, grantTypes []OIDCGrantType, appType OIDCApplicationType, redirectUris []string) { func checkRedirectURIs(compliance *Compliance, grantTypes []OIDCGrantType, appType OIDCApplicationType, redirectUris []string) {
if len(redirectUris) == 0 { // See #5684 for OIDCGrantTypeDeviceCode and redirectUris further explanation
if len(redirectUris) == 0 && (!containsOIDCGrantType(grantTypes, OIDCGrantTypeDeviceCode) || (containsOIDCGrantType(grantTypes, OIDCGrantTypeDeviceCode) && containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode))) {
compliance.NoneCompliant = true compliance.NoneCompliant = true
compliance.Problems = append([]string{"Application.OIDC.V1.NoRedirectUris"}, compliance.Problems...) compliance.Problems = append([]string{"Application.OIDC.V1.NoRedirectUris"}, compliance.Problems...)
} }

View File

@ -236,6 +236,11 @@ func Test_checkGrantTypesCombination(t *testing.T) {
}, },
grantTypes: []OIDCGrantType{OIDCGrantTypeImplicit, OIDCGrantTypeRefreshToken}, grantTypes: []OIDCGrantType{OIDCGrantTypeImplicit, OIDCGrantTypeRefreshToken},
}, },
{
name: "device code flow and refresh token doesnt require OIDCGrantTypeImplicit",
want: &Compliance{},
grantTypes: []OIDCGrantType{OIDCGrantTypeDeviceCode, OIDCGrantTypeRefreshToken},
},
{ {
name: "refresh token and authorization code", name: "refresh token and authorization code",
want: &Compliance{}, want: &Compliance{},