diff --git a/ui-ngx/src/app/core/http/admin.service.ts b/ui-ngx/src/app/core/http/admin.service.ts index 1fb6f717c3..38a7c6e5e9 100644 --- a/ui-ngx/src/app/core/http/admin.service.ts +++ b/ui-ngx/src/app/core/http/admin.service.ts @@ -20,6 +20,7 @@ import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { AdminSettings, + ClientProviderTemplated, MailServerSettings, OAuth2Settings, SecuritySettings, @@ -63,8 +64,8 @@ export class AdminService { return this.http.get(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config)); } - public getOAuth2Template(config?: RequestConfig): Observable { - return this.http.get(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config)); + public getOAuth2Template(config?: RequestConfig): Observable> { + return this.http.get>(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config)); } public saveOAuth2Settings(OAuth2Setting: OAuth2Settings, diff --git a/ui-ngx/src/app/core/services/menu.service.ts b/ui-ngx/src/app/core/services/menu.service.ts index bb39cfa415..7d3503a613 100644 --- a/ui-ngx/src/app/core/services/menu.service.ts +++ b/ui-ngx/src/app/core/services/menu.service.ts @@ -120,9 +120,9 @@ export class MenuService { icon: 'security' }, { - name: 'admin.oauth2.settings', + name: 'admin.oauth2.oauth2', type: 'link', - path: '/settings/oauth2-settings', + path: '/settings/oauth2', icon: 'security' } ] @@ -246,13 +246,13 @@ export class MenuService { icon: 'settings', pages: [ { - name: 'admin.oauth2.settings', + name: 'admin.oauth2.oauth2', type: 'link', - path: '/settings/oauth2-settings', + path: '/settings/oauth2', icon: 'security' } ] - }) + }); } return sections; diff --git a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts index a6b18cfd29..16635ef53f 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/admin-routing.module.ts @@ -81,14 +81,14 @@ const routes: Routes = [ } }, { - path: 'oauth2-settings', + path: 'oauth2', component: OAuth2SettingsComponent, canDeactivate: [ConfirmOnExitGuard], data: { auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'admin.oauth2.settings', + title: 'admin.oauth2.oauth2', breadcrumb: { - label: 'admin.oauth2.settings', + label: 'admin.oauth2.oauth2', icon: 'security' } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html index bb77210ba8..fce4f0339f 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.html @@ -19,7 +19,7 @@
- admin.oauth2.settings + admin.oauth2.oauth2
@@ -91,7 +91,7 @@
- Login Provider + admin.oauth2.login-provider {{ provider | uppercase }} @@ -117,223 +117,254 @@ - - -
- - admin.oauth2.access-token-uri - - - {{ 'admin.oauth2.access-token-uri-required' | translate }} - - - {{ 'admin.oauth2.uri-pattern-error' | translate }} - - - - - admin.oauth2.authorization-uri - - - {{ 'admin.oauth2.authorization-uri-required' | translate }} - - - {{ 'admin.oauth2.uri-pattern-error' | translate }} - - -
- -
- - admin.oauth2.jwk-set-uri - - - {{ 'admin.oauth2.jwk-set-uri-required' | translate }} - - - {{ 'admin.oauth2.uri-pattern-error' | translate }} - - - - - admin.oauth2.user-info-uri - - - {{ 'admin.oauth2.user-info-uri-required' | translate }} - - - {{ 'admin.oauth2.uri-pattern-error' | translate }} - - -
- - - admin.oauth2.client-authentication-method - - - {{ clientAuthenticationMethod | uppercase }} - - - - -
- - admin.oauth2.login-button-label - - - {{ 'admin.oauth2.login-button-label-required' | translate }} - - - - - admin.oauth2.login-button-icon - - -
- - - admin.oauth2.scope - - - {{scope}} - cancel - - - - - {{ 'admin.oauth2.jwk-set-uri-required' | translate }} - - - -
- - - admin.oauth2.user-name-attribute-name - - - {{ 'admin.oauth2.user-name-attribute-name-required' | translate }} - - - -
-
- - {{ 'admin.oauth2.allow-user-creation' | translate }} - - - {{ 'admin.oauth2.activate-user' | translate }} - -
- - - admin.oauth2.type - - - {{ converterTypeExternalUser }} - - - - -
- - admin.oauth2.email-attribute-key - - - {{ 'admin.oauth2.email-attribute-key-required' | translate }} - - - -
+ + + + {{ 'admin.oauth2.custom-setting' | translate }} + + + + + +
- admin.oauth2.first-name-attribute-key - + admin.oauth2.access-token-uri + + + + {{ 'admin.oauth2.access-token-uri-required' | translate }} + + + {{ 'admin.oauth2.uri-pattern-error' | translate }} + - admin.oauth2.last-name-attribute-key - + admin.oauth2.authorization-uri + + + + {{ 'admin.oauth2.authorization-uri-required' | translate }} + + + {{ 'admin.oauth2.uri-pattern-error' | translate }} +
- - admin.oauth2.tenant-name-strategy - - - {{ tenantNameStrategy }} - - + + admin.oauth2.jwk-set-uri + + + + {{ 'admin.oauth2.uri-pattern-error' | translate }} + - - admin.oauth2.tenant-name-pattern - - - {{ 'admin.oauth2.tenant-name-pattern-required' | translate }} + + admin.oauth2.user-info-uri + + + + {{ 'admin.oauth2.user-info-uri-required' | translate }} + + + {{ 'admin.oauth2.uri-pattern-error' | translate }}
- admin.oauth2.customer-name-pattern - + admin.oauth2.client-authentication-method + + + {{ clientAuthenticationMethod | uppercase }} + + -
+
- admin.oauth2.default-dashboard-name - + admin.oauth2.login-button-label + + + {{ 'admin.oauth2.login-button-label-required' | translate }} + - - {{ 'admin.oauth2.always-fullscreen' | translate}} - + + admin.oauth2.login-button-icon + +
-
- -
- - admin.oauth2.url - - - {{ 'admin.oauth2.url-required' | translate }} - - - {{ 'admin.oauth2.url-pattern' | translate }} + +
+
+ + {{ 'admin.oauth2.allow-user-creation' | translate }} + + + {{ 'admin.oauth2.activate-user' | translate }} + +
+
+ + + admin.oauth2.scope + + + {{scope}} + cancel + + + + + + + + + admin.oauth2.user-name-attribute-name + + + {{ 'admin.oauth2.user-name-attribute-name-required' | translate }} -
+
- common.username - + admin.oauth2.type + + + {{ converterTypeExternalUser }} + + - - common.password - - -
-
-
-
-
+
+ + admin.oauth2.email-attribute-key + + + {{ 'admin.oauth2.email-attribute-key-required' | translate }} + + + +
+ + admin.oauth2.first-name-attribute-key + + + + + admin.oauth2.last-name-attribute-key + + +
+ +
+ + admin.oauth2.tenant-name-strategy + + + {{ tenantNameStrategy }} + + + + + + admin.oauth2.tenant-name-pattern + + + {{ 'admin.oauth2.tenant-name-pattern-required' | translate }} + + +
+ + + admin.oauth2.customer-name-pattern + + + +
+ + admin.oauth2.default-dashboard-name + + + + + {{ 'admin.oauth2.always-fullscreen' | translate}} + +
+
+ +
+ + admin.oauth2.url + + + {{ 'admin.oauth2.url-required' | translate }} + + + {{ 'admin.oauth2.url-pattern' | translate }} + + + +
+ + common.username + + + + + common.password + + +
+
+
+ + +
+ diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss index d174ba2dcf..ae7e94a5ac 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.scss @@ -21,9 +21,32 @@ .registration-card{ margin-bottom: 8px; border: 1px solid rgba(0, 0, 0, 0.2); + + .custom-settings{ + font-size: 16px; + .mat-expansion-panel-header{ + padding: 0 2px; + } + } } .container{ margin-bottom: 16px; } } + +:host ::ng-deep{ + .registration-card{ + .custom-settings{ + .mat-expansion-panel-body{ + padding: 0 2px 16px; + } + .mat-tab-label{ + text-transform: none; + } + .mat-form-field-suffix .mat-icon-button .mat-icon{ + font-size: 18px; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts index 0459213ee9..074236c006 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/oauth2-settings.component.ts @@ -18,6 +18,7 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, ViewContainerR import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ClientAuthenticationMethod, + ClientProviderTemplated, ClientRegistration, DomainParams, MapperConfigType, @@ -50,9 +51,24 @@ import { }) export class OAuth2SettingsComponent extends PageComponent implements OnInit, HasConfirmForm, OnDestroy { - private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/; + private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.,?+=&%@\-/]*)?$/; private subscriptions: Subscription[] = []; - private templates = []; + private templates = new Map(); + private defaultProvider = { + providerName: 'Custom', + clientAuthenticationMethod: 'Post', + userNameAttributeName: 'email', + mapperConfig: { + allowUserCreation: true, + activateUser: false, + type: 'BASIC', + basic: { + emailAttributeKey: 'email', + tenantNameStrategy: 'DOMAIN', + alwaysFullScreen: false + } + } + }; readonly separatorKeysCodes: number[] = [ENTER, COMMA]; @@ -99,9 +115,9 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha }); } - private initTemplates(templates: any): void { - this.templates = templates; - templates.map(provider => this.templateProvider.push(provider.name)); + private initTemplates(templates: ClientProviderTemplated[]): void { + templates.map(provider => this.templates.set(provider.name, provider)); + this.templateProvider.push(...Array.from(this.templates.keys())); this.templateProvider.sort(); } @@ -118,7 +134,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha tenantNamePattern: [null], customerNamePattern: [null], defaultDashboardName: [null], - alwaysFullScreen: [false], + alwaysFullScreen: [false] }); this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { @@ -209,7 +225,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha accessTokenUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], authorizationUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], scope: this.fb.array([], [Validators.required]), - jwkSetUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], + jwkSetUri: ['', [Validators.pattern(this.URL_REGEXP)]], userInfoUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], clientAuthenticationMethod: ['POST', [Validators.required]], userNameAttributeName: ['email', [Validators.required]], @@ -233,6 +249,27 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha } })); + this.subscriptions.push(clientRegistration.get('providerName').valueChanges.subscribe((provider) => { + (clientRegistration.get('scope') as FormArray).clear(); + if (provider === 'Custom') { + 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); + template.scope.forEach(() => { + (clientRegistration.get('scope') as FormArray).push(this.fb.control('')); + }); + clientRegistration.get('accessTokenUri').disable(); + clientRegistration.get('authorizationUri').disable(); + clientRegistration.get('jwkSetUri').disable(); + clientRegistration.get('userInfoUri').disable(); + clientRegistration.patchValue(this.templates.get(provider), {emitEvent: false}); + } + })); + if (registrationData) { registrationData.scope.forEach(() => { (clientRegistration.get('scope') as FormArray).push(this.fb.control('')); @@ -366,4 +403,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha } }); } + + toggleEditMode(control: AbstractControl, path: string) { + control.get(path).disabled ? control.get(path).enable() : control.get(path).disable(); + } } diff --git a/ui-ngx/src/app/shared/models/settings.models.ts b/ui-ngx/src/app/shared/models/settings.models.ts index 2016a309c6..8fe83aee09 100644 --- a/ui-ngx/src/app/shared/models/settings.models.ts +++ b/ui-ngx/src/app/shared/models/settings.models.ts @@ -14,6 +14,9 @@ /// limitations under the License. /// +import { EntityId } from '@shared/models/id/entity-id'; +import { TenantId } from '@shared/models/id/tenant-id'; + export const smtpPortPattern: RegExp = /^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/; export interface AdminSettings { @@ -75,6 +78,17 @@ export interface DomainParams { clientRegistrations: ClientRegistration[]; } +export interface ClientProviderTemplated extends ClientRegistration{ + additionalInfo: string; + comment: string; + createdTime: number; + helpLink: string; + id: EntityId; + name: string; + providerId: string; + tenantId: TenantId; +} + export interface ClientRegistration { loginButtonLabel: string; loginButtonIcon: string; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index aea8c1cfe4..802575c0ff 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -128,7 +128,7 @@ "add-provider": "Add provider", "settings": "Settings", "oauth2": { - "settings": "OAuth2 Settings", + "oauth2": "OAuth2", "registration-id": "Registration ID", "registration-id-required": "Registration ID is required.", "registration-id-unique": "Registration ID need to unique for the system.", @@ -145,7 +145,6 @@ "redirect-uri-template": "Redirect URI template", "redirect-uri-template-required": "Redirect URI template is required.", "jwk-set-uri": "JSON Web Key URI", - "jwk-set-uri-required": "JSON Web Key URI is required.", "user-info-uri": "User info URI", "user-info-uri-required": "User info URI is required.", "client-authentication-method": "Client authentication method", @@ -173,7 +172,11 @@ "delete-domain-title": "Are you sure you want to delete the domain '{{domainName}}'?", "delete-domain-text": "Be careful, after the confirmation a domain and all registration data will be unavailable.", "delete-registration-title": "Are you sure you want to delete the registration '{{name}}'?", - "delete-registration-text": "Be careful, after the confirmation a registration data will be unavailable." + "delete-registration-text": "Be careful, after the confirmation a registration data will be unavailable.", + "login-provider": "Login provider", + "custom-setting": "Custom settings", + "general": "General", + "mapper": "Mapper" } }, "alarm": {