@ -15,25 +15,24 @@
///
import { Component , Inject , OnDestroy , OnInit } from '@angular/core' ;
import { AbstractControl , FormArray , FormBuilder , FormGroup , Validators } from '@angular/forms' ;
import { AbstractControl , FormArray , FormBuilder , FormGroup , ValidationErrors , Validat ors } from '@angular/forms' ;
import {
ClientAuthenticationMethod ,
ClientProviderTemplated ,
ClientRegistration ,
DomainInfo ,
DomainSchema ,
domainSchemaTranslations ,
DomainsParam ,
MapperConfig ,
MapperConfigBasic ,
MapperConfigCustom ,
MapperConfigType ,
OAuth2Settings ,
OAuth2ClientRegistrationTemplate ,
OAuth2ClientsDomainParams ,
OAuth2ClientsParams ,
TenantNameStrategy
} from '@shared/models/settings.models' ;
} from '@shared/models/oauth2 .models' ;
import { Store } from '@ngrx/store' ;
import { AppState } from '@core/core.state' ;
import { AdminService } from '@core/http/admin.service' ;
import { PageComponent } from '@shared/components/page.component' ;
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard' ;
import { COMMA , ENTER } from '@angular/cdk/keycodes' ;
@ -42,7 +41,8 @@ import { WINDOW } from '@core/services/window.service';
import { forkJoin , Subscription } from 'rxjs' ;
import { DialogService } from '@core/services/dialog.service' ;
import { TranslateService } from '@ngx-translate/core' ;
import { isDefined } from '@core/utils' ;
import { isDefined , isDefinedAndNotNull } from '@core/utils' ;
import { OAuth2Service } from '@core/http/oauth2.service' ;
@Component ( {
selector : 'tb-oauth2-settings' ,
@ -53,7 +53,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.,?+=&%@\-/]*)?$/ ;
private subscriptions : Subscription [ ] = [ ] ;
private templates = new Map < string , ClientProviderTemplated > ( ) ;
private templates = new Map < string , OAuth2ClientRegistrationTemplate > ( ) ;
private defaultProvider = {
additionalInfo : {
providerName : 'Custom'
@ -75,10 +75,11 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
readonly separatorKeysCodes : number [ ] = [ ENTER , COMMA ] ;
oauth2SettingsForm : FormGroup ;
oauth2Settings : OAuth2Setting s;
auth2ClientsParams : OAuth2ClientsParam s;
clientAuthenticationMethods = Object . keys ( ClientAuthenticationMethod ) ;
converterTypesExternalUser = Object . keys ( MapperConfigType ) ;
mapperConfigType = MapperConfigType ;
mapperConfigTypes = Object . keys ( MapperConfigType ) ;
tenantNameStrategies = Object . keys ( TenantNameStrategy ) ;
protocols = Object . keys ( DomainSchema ) ;
domainSchemaTranslations = domainSchemaTranslations ;
@ -86,7 +87,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
templateProvider = [ 'Custom' ] ;
constructor ( protected store : Store < AppState > ,
private adminService : Admin Service,
private oauth2Service : OAuth2 Service,
private fb : FormBuilder ,
private dialogService : DialogService ,
private translate : TranslateService ,
@ -97,13 +98,13 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
ngOnInit ( ) : void {
this . buildOAuth2SettingsForm ( ) ;
forkJoin ( [
this . admin Service. getOAuth2Template ( ) ,
this . admin Service. getOAuth2Settings ( )
this . oauth2 Service. getOAuth2Template ( ) ,
this . oauth2 Service. getOAuth2Settings ( )
] ) . subscribe (
( [ templates , oauth2Setting s] ) = > {
( [ templates , auth2ClientsParam s] ) = > {
this . initTemplates ( templates ) ;
this . oauth2Settings = oauth2Setting s;
this . initOAuth2Settings ( this . oauth2Setting s) ;
this . auth2ClientsParams = auth2ClientsParam s;
this . initOAuth2Settings ( this . auth2ClientsParam s) ;
}
) ;
}
@ -115,8 +116,11 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
} ) ;
}
private initTemplates ( templates : ClientProviderTemplated [ ] ) : void {
templates . map ( provider = > this . templates . set ( provider . name , provider ) ) ;
private initTemplates ( templates : OAuth2ClientRegistrationTemplate [ ] ) : void {
templates . map ( provider = > {
delete provider . additionalInfo ;
this . templates . set ( provider . name , provider ) ;
} ) ;
this . templateProvider . push ( . . . Array . from ( this . templates . keys ( ) ) ) ;
this . templateProvider . sort ( ) ;
}
@ -169,10 +173,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
} ) ;
}
private initOAuth2Settings ( oauth2Settings : OAuth2Setting s) : void {
if ( oauth2Setting s) {
this . oauth2SettingsForm . patchValue ( { enabled : oauth2Setting s.enabled} , { emitEvent : false } ) ;
oauth2Setting s. domainsParams . forEach ( ( domain ) = > {
private initOAuth2Settings ( auth2ClientsParams : OAuth2ClientsParam s) : void {
if ( auth2ClientsParam s) {
this . oauth2SettingsForm . patchValue ( { enabled : auth2ClientsParam s.enabled} , { emitEvent : false } ) ;
auth2ClientsParam s. domainsParams . forEach ( ( domain ) = > {
this . domainsParams . push ( this . buildDomainsForm ( domain ) ) ;
} ) ;
}
@ -204,17 +208,17 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
return this . translate . instant ( 'admin.oauth2.new-domain' ) ;
}
private buildDomainsForm ( domainParams? : DomainsParam ) : FormGroup {
private buildDomainsForm ( auth2ClientsDomainParams? : OAuth2ClientsDomainParams ) : FormGroup {
const formDomain = this . fb . group ( {
domainInfos : this.fb.array ( [ ] , Validators . required ) ,
clientRegistrations : this.fb.array ( [ ] , Validators . required )
} ) ;
if ( d omainParams) {
d omainParams. domainInfos . forEach ( ( domain ) = > {
if ( auth2ClientsD omainParams) {
auth2ClientsD omainParams. domainInfos . forEach ( ( domain ) = > {
this . clientDomainInfos ( formDomain ) . push ( this . buildDomainForm ( domain ) ) ;
} ) ;
d omainParams. clientRegistrations . forEach ( ( registration ) = > {
auth2ClientsD omainParams. clientRegistrations . forEach ( ( registration ) = > {
this . clientDomainProviders ( formDomain ) . push ( this . buildProviderForm ( registration ) ) ;
} ) ;
} else {
@ -235,10 +239,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
return domain ;
}
private buildProviderForm ( registrationData ? : ClientRegistration ) : FormGroup {
private buildProviderForm ( clientRegistration ? : ClientRegistration ) : FormGroup {
let additionalInfo = null ;
if ( registrationData ? . additionalInfo ) {
additionalInfo = JSON . parse ( registrationData . additionalInfo ) ;
if ( isDefinedAndNotNull ( clientRegistration ? . additionalInfo ) ) {
additionalInfo = clientRegistration . additionalInfo ;
if ( this . templateProvider . indexOf ( additionalInfo . providerName ) === - 1 ) {
additionalInfo . providerName = 'Custom' ;
}
@ -248,73 +252,80 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
defaultProviderName = 'Google' ;
}
const clientRegistration = this . fb . group ( {
id : this.fb.group ( {
id : [ registrationData ? . id ? . id ? registrationData.id.id : null ] ,
entityType : [ registrationData ? . id ? . entityType ? registrationData.id.entityType : null ]
} ) ,
const clientRegistrationFormGroup = this . fb . group ( {
additionalInfo : this.fb.group ( {
providerName : [ additionalInfo ? . providerName ? additionalInfo?.providerName : defaultProviderName , Validators . required ]
} ) ,
loginButtonLabel : [ registrationData ? . loginButtonLabel ? registrationData .loginButtonLabel : null , Validators . required ] ,
loginButtonIcon : [ registrationData ? . loginButtonIcon ? registrationData .loginButtonIcon : null ] ,
clientId : [ registrationData ? . clientId ? registrationData . clientId : '' , Validators . required ] ,
clientSecret : [ registrationData ? . clientSecret ? registrationData . clientSecret : '' , Validators . required ] ,
accessTokenUri : [ registrationData ? . accessTokenUri ? registrationData . accessTokenUri : '' ,
loginButtonLabel : [ clientRegistration ? . loginButtonLabel ? clientRegistration.loginButtonLabel : null , Validators . required ] ,
loginButtonIcon : [ clientRegistration ? . loginButtonIcon ? clientRegistration .loginButtonIcon : null ] ,
clientId : [ clientRegistration ? . clientId ? clientRegistration . clientId : '' , Validators . required ] ,
clientSecret : [ clientRegistration ? . clientSecret ? clientRegistration . clientSecret : '' , Validators . required ] ,
accessTokenUri : [ clientRegistration ? . accessTokenUri ? clientRegistration . accessTokenUri : '' ,
[ Validators . required ,
Validators . pattern ( this . URL_REGEXP ) ] ] ,
authorizationUri : [ registrationData ? . authorizationUri ? registrationData . authorizationUri : '' ,
authorizationUri : [ clientRegistration ? . authorizationUri ? clientRegistration . authorizationUri : '' ,
[ Validators . required ,
Validators . pattern ( this . URL_REGEXP ) ] ] ,
scope : this.fb.array ( registrationData ? . scope ? registrationData . scope : [ ] , Validators . required ) ,
jwkSetUri : [ registrationData ? . jwkSetUri ? registrationData . jwkSetUri : '' , Validators . pattern ( this . URL_REGEXP ) ] ,
userInfoUri : [ registrationData ? . userInfoUri ? registrationData . userInfoUri : '' ,
scope : this.fb.array ( clientRegistration ? . scope ? clientRegistration . scope : [ ] , this . validateScope ) ,
jwkSetUri : [ clientRegistration ? . jwkSetUri ? clientRegistration . jwkSetUri : '' , Validators . pattern ( this . URL_REGEXP ) ] ,
userInfoUri : [ clientRegistration ? . userInfoUri ? clientRegistration . userInfoUri : '' ,
[ Validators . required ,
Validators . pattern ( this . URL_REGEXP ) ] ] ,
clientAuthenticationMethod : [
registrationData ? . clientAuthenticationMethod ? registrationData .clientAuthenticationMethod : ClientAuthenticationMethod.POST ,
clientRegistration ? . clientAuthenticationMethod ? clientRegistration .clientAuthenticationMethod : ClientAuthenticationMethod.POST ,
Validators . required ] ,
userNameAttributeName : [
registrationData ? . userNameAttributeName ? registrationData . userNameAttributeName : 'email' , Validators . required ] ,
clientRegistration ? . userNameAttributeName ? clientRegistration . userNameAttributeName : 'email' , Validators . required ] ,
mapperConfig : this.fb.group ( {
allowUserCreation : [ registrationData ? . mapperConfig ? . allowUserCreation ? registrationData.mapperConfig.allowUserCreation : true ] ,
activateUser : [ registrationData ? . mapperConfig ? . activateUser ? registrationData.mapperConfig.activateUser : false ] ,
type : [ registrationData ? . mapperConfig ? . type ? registrationData.mapperConfig.type : MapperConfigType.BASIC , Validators . required ]
allowUserCreation : [
clientRegistration ? . mapperConfig ? . allowUserCreation ? clientRegistration.mapperConfig.allowUserCreation : true
] ,
activateUser : [ clientRegistration ? . mapperConfig ? . activateUser ? clientRegistration.mapperConfig.activateUser : false ] ,
type : [
clientRegistration ? . mapperConfig ? . type ? clientRegistration.mapperConfig.type : MapperConfigType.BASIC , Validators . required
]
}
)
} ) ;
if ( registrationData ) {
this . changeMapperConfigType ( clientRegistration , registrationData . mapperConfig . type , registrationData . mapperConfig ) ;
if ( clientRegistration ) {
this . changeMapperConfigType ( clientRegistrationFormGroup , clientRegistration . mapperConfig . type , clientRegistration . mapperConfig ) ;
} else {
this . changeMapperConfigType ( clientRegistration , MapperConfigType . BASIC ) ;
this . setProviderDefaultValue ( defaultProviderName , clientRegistration ) ;
this . changeMapperConfigType ( clientRegistrationFormGroup , MapperConfigType . BASIC ) ;
this . setProviderDefaultValue ( defaultProviderName , clientRegistrationFormGroup ) ;
}
this . subscriptions . push ( clientRegistration . get ( 'mapperConfig.type' ) . valueChanges . subscribe ( ( value ) = > {
this . changeMapperConfigType ( clientRegistration , value ) ;
this . subscriptions . push ( clientRegistrationFormGroup . get ( 'mapperConfig.type' ) . valueChanges . subscribe ( ( value ) = > {
this . changeMapperConfigType ( clientRegistrationFormGroup , value ) ;
} ) ) ;
this . subscriptions . push ( clientRegistration . get ( 'additionalInfo.providerName' ) . valueChanges . subscribe ( ( provider ) = > {
( clientRegistration . get ( 'scope' ) as FormArray ) . clear ( ) ;
this . setProviderDefaultValue ( provider , clientRegistration ) ;
this . subscriptions . push ( clientRegistrationFormGroup . get ( 'additionalInfo.providerName' ) . valueChanges . subscribe ( ( provider ) = > {
( clientRegistrationFormGroup . get ( 'scope' ) as FormArray ) . clear ( ) ;
this . setProviderDefaultValue ( provider , clientRegistrationFormGroup ) ;
} ) ) ;
return clientRegistration ;
return clientRegistrationFormGroup ;
}
private validateScope ( control : AbstractControl ) : ValidationErrors | null {
const scope : string [ ] = control . value ;
if ( ! scope || ! scope . length ) {
return {
required : true
} ;
}
return null ;
}
private setProviderDefaultValue ( provider : string , clientRegistration : FormGroup ) {
if ( provider === 'Custom' ) {
const defaultSettings = { . . . this . defaultProvider , . . . { id : clientRegistration.get ( 'id' ) . value } } ;
clientRegistration . reset ( defaultSettings , { emitEvent : false } ) ;
clientRegistration . reset ( this . defaultProvider , { emitEvent : false } ) ;
clientRegistration . get ( 'accessTokenUri' ) . enable ( ) ;
clientRegistration . get ( 'authorizationUri' ) . enable ( ) ;
clientRegistration . get ( 'jwkSetUri' ) . enable ( ) ;
clientRegistration . get ( 'userInfoUri' ) . enable ( ) ;
} else {
const template = this . templates . get ( provider ) ;
delete template . id ;
delete template . additionalInfo ;
template . clientId = '' ;
template . clientSecret = '' ;
template . scope . forEach ( ( ) = > {
@ -324,44 +335,33 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
clientRegistration . get ( 'authorizationUri' ) . disable ( ) ;
clientRegistration . get ( 'jwkSetUri' ) . disable ( ) ;
clientRegistration . get ( 'userInfoUri' ) . disable ( ) ;
clientRegistration . patchValue ( template , { emitEvent : false } ) ;
clientRegistration . patchValue ( template ) ;
}
}
private changeMapperConfigType ( control : AbstractControl , type : MapperConfigType , predefinedValue? : MapperConfig ) {
const mapperConfig = control . get ( 'mapperConfig' ) as FormGroup ;
if ( type === MapperConfigType . BASIC ) {
mapperConfig . removeControl ( 'custom' ) ;
mapperConfig . addControl ( 'basic' , this . formBasicGroup ( predefinedValue ? . basic ) ) ;
} else {
if ( type === MapperConfigType . CUSTOM ) {
mapperConfig . removeControl ( 'basic' ) ;
mapperConfig . addControl ( 'custom' , this . formCustomGroup ( predefinedValue ? . custom ) ) ;
} else {
mapperConfig . removeControl ( 'custom' ) ;
mapperConfig . addControl ( 'basic' , this . formBasicGroup ( predefinedValue ? . basic ) ) ;
}
}
save ( ) : void {
const setting = this . prepareFormValue ( this . oauth2SettingsForm . getRawValue ( ) ) ;
this . admin Service. saveOAuth2Settings ( setting ) . subscribe (
const setting = this . oauth2SettingsForm . getRawValue ( ) ;
this . oauth2 Service. saveOAuth2Settings ( setting ) . subscribe (
( oauth2Settings ) = > {
this . oauth2Setting s = oauth2Settings ;
this . oauth2SettingsForm . markAsPristine ( ) ;
this . auth2ClientsParam s = oauth2Settings ;
this . oauth2SettingsForm . patchValue ( this . oauth2SettingsForm , { emitEvent : false } ) ;
this . oauth2SettingsForm . markAsUntouched ( ) ;
this . oauth2SettingsForm . markAsPristine ( ) ;
}
) ;
}
private prepareFormValue ( formValue : OAuth2Settings ) : OAuth2Settings {
formValue . domainsParams . forEach ( ( setting , index ) = > {
setting . clientRegistrations . forEach ( ( registration ) = > {
registration . additionalInfo = JSON . stringify ( registration . additionalInfo ) ;
if ( registration . id . id === null ) {
delete registration . id ;
}
} ) ;
} ) ;
return formValue ;
}
confirmForm ( ) : FormGroup {
return this . oauth2SettingsForm ;
}
@ -451,6 +451,10 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
return controller . get ( 'additionalInfo.providerName' ) . value ;
}
isCustomProvider ( controller : AbstractControl ) : boolean {
return this . getProviderName ( controller ) === 'Custom' ;
}
getHelpLink ( controller : AbstractControl ) : string {
const provider = controller . get ( 'additionalInfo.providerName' ) . value ;
if ( provider === null || provider === 'Custom' ) {