Commit ae92f065e68d996432823928f2b2a64e532c5f81

Authored by Vladyslav_Prykhodko
1 parent c3407bfd

Add select login provider templated

@@ -20,6 +20,7 @@ import { Observable } from 'rxjs'; @@ -20,6 +20,7 @@ import { Observable } from 'rxjs';
20 import { HttpClient } from '@angular/common/http'; 20 import { HttpClient } from '@angular/common/http';
21 import { 21 import {
22 AdminSettings, 22 AdminSettings,
  23 + ClientProviderTemplated,
23 MailServerSettings, 24 MailServerSettings,
24 OAuth2Settings, 25 OAuth2Settings,
25 SecuritySettings, 26 SecuritySettings,
@@ -63,8 +64,8 @@ export class AdminService { @@ -63,8 +64,8 @@ export class AdminService {
63 return this.http.get<OAuth2Settings>(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config)); 64 return this.http.get<OAuth2Settings>(`/api/oauth2/config`, defaultHttpOptionsFromConfig(config));
64 } 65 }
65 66
66 - public getOAuth2Template(config?: RequestConfig): Observable<any> {  
67 - return this.http.get<any>(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config)); 67 + public getOAuth2Template(config?: RequestConfig): Observable<Array<ClientProviderTemplated>> {
  68 + return this.http.get<Array<ClientProviderTemplated>>(`/api/oauth2/config/template`, defaultHttpOptionsFromConfig(config));
68 } 69 }
69 70
70 public saveOAuth2Settings(OAuth2Setting: OAuth2Settings, 71 public saveOAuth2Settings(OAuth2Setting: OAuth2Settings,
@@ -120,9 +120,9 @@ export class MenuService { @@ -120,9 +120,9 @@ export class MenuService {
120 icon: 'security' 120 icon: 'security'
121 }, 121 },
122 { 122 {
123 - name: 'admin.oauth2.settings', 123 + name: 'admin.oauth2.oauth2',
124 type: 'link', 124 type: 'link',
125 - path: '/settings/oauth2-settings', 125 + path: '/settings/oauth2',
126 icon: 'security' 126 icon: 'security'
127 } 127 }
128 ] 128 ]
@@ -246,13 +246,13 @@ export class MenuService { @@ -246,13 +246,13 @@ export class MenuService {
246 icon: 'settings', 246 icon: 'settings',
247 pages: [ 247 pages: [
248 { 248 {
249 - name: 'admin.oauth2.settings', 249 + name: 'admin.oauth2.oauth2',
250 type: 'link', 250 type: 'link',
251 - path: '/settings/oauth2-settings', 251 + path: '/settings/oauth2',
252 icon: 'security' 252 icon: 'security'
253 } 253 }
254 ] 254 ]
255 - }) 255 + });
256 } 256 }
257 257
258 return sections; 258 return sections;
@@ -81,14 +81,14 @@ const routes: Routes = [ @@ -81,14 +81,14 @@ const routes: Routes = [
81 } 81 }
82 }, 82 },
83 { 83 {
84 - path: 'oauth2-settings', 84 + path: 'oauth2',
85 component: OAuth2SettingsComponent, 85 component: OAuth2SettingsComponent,
86 canDeactivate: [ConfirmOnExitGuard], 86 canDeactivate: [ConfirmOnExitGuard],
87 data: { 87 data: {
88 auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], 88 auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN],
89 - title: 'admin.oauth2.settings', 89 + title: 'admin.oauth2.oauth2',
90 breadcrumb: { 90 breadcrumb: {
91 - label: 'admin.oauth2.settings', 91 + label: 'admin.oauth2.oauth2',
92 icon: 'security' 92 icon: 'security'
93 } 93 }
94 } 94 }
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 <mat-card class="settings-card"> 19 <mat-card class="settings-card">
20 <mat-card-title> 20 <mat-card-title>
21 <div fxLayout="row"> 21 <div fxLayout="row">
22 - <span class="mat-headline" translate>admin.oauth2.settings</span> 22 + <span class="mat-headline" translate>admin.oauth2.oauth2</span>
23 <span fxFlex></span> 23 <span fxFlex></span>
24 <div tb-help="oauth2Settings"></div> 24 <div tb-help="oauth2Settings"></div>
25 </div> 25 </div>
@@ -91,7 +91,7 @@ @@ -91,7 +91,7 @@
91 <ng-template matExpansionPanelContent> 91 <ng-template matExpansionPanelContent>
92 <section [formGroupName]="j"> 92 <section [formGroupName]="j">
93 <mat-form-field fxFlex class="mat-block"> 93 <mat-form-field fxFlex class="mat-block">
94 - <mat-label translate>Login Provider</mat-label> 94 + <mat-label translate>admin.oauth2.login-provider</mat-label>
95 <mat-select formControlName="providerName"> 95 <mat-select formControlName="providerName">
96 <mat-option *ngFor="let provider of templateProvider" [value]="provider"> 96 <mat-option *ngFor="let provider of templateProvider" [value]="provider">
97 {{ provider | uppercase }} 97 {{ provider | uppercase }}
@@ -117,223 +117,254 @@ @@ -117,223 +117,254 @@
117 </mat-form-field> 117 </mat-form-field>
118 </div> 118 </div>
119 119
120 - <mat-tab-group dynamicHeight>  
121 - <mat-tab label="General">  
122 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" style="margin-top: 16px;">  
123 - <mat-form-field fxFlex class="mat-block">  
124 - <mat-label translate>admin.oauth2.access-token-uri</mat-label>  
125 - <input matInput formControlName="accessTokenUri" required>  
126 - <mat-error *ngIf="registration.get('accessTokenUri').hasError('required')">  
127 - {{ 'admin.oauth2.access-token-uri-required' | translate }}  
128 - </mat-error>  
129 - <mat-error *ngIf="registration.get('accessTokenUri').hasError('pattern')">  
130 - {{ 'admin.oauth2.uri-pattern-error' | translate }}  
131 - </mat-error>  
132 - </mat-form-field>  
133 -  
134 - <mat-form-field fxFlex class="mat-block">  
135 - <mat-label translate>admin.oauth2.authorization-uri</mat-label>  
136 - <input matInput formControlName="authorizationUri" required>  
137 - <mat-error *ngIf="registration.get('authorizationUri').hasError('required')">  
138 - {{ 'admin.oauth2.authorization-uri-required' | translate }}  
139 - </mat-error>  
140 - <mat-error *ngIf="registration.get('authorizationUri').hasError('pattern')">  
141 - {{ 'admin.oauth2.uri-pattern-error' | translate }}  
142 - </mat-error>  
143 - </mat-form-field>  
144 - </div>  
145 -  
146 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">  
147 - <mat-form-field fxFlex class="mat-block">  
148 - <mat-label translate>admin.oauth2.jwk-set-uri</mat-label>  
149 - <input matInput formControlName="jwkSetUri" required>  
150 - <mat-error *ngIf="registration.get('jwkSetUri').hasError('required')">  
151 - {{ 'admin.oauth2.jwk-set-uri-required' | translate }}  
152 - </mat-error>  
153 - <mat-error *ngIf="registration.get('jwkSetUri').hasError('pattern')">  
154 - {{ 'admin.oauth2.uri-pattern-error' | translate }}  
155 - </mat-error>  
156 - </mat-form-field>  
157 -  
158 - <mat-form-field fxFlex class="mat-block">  
159 - <mat-label translate>admin.oauth2.user-info-uri</mat-label>  
160 - <input matInput formControlName="userInfoUri" required>  
161 - <mat-error *ngIf="registration.get('userInfoUri').hasError('required')">  
162 - {{ 'admin.oauth2.user-info-uri-required' | translate }}  
163 - </mat-error>  
164 - <mat-error *ngIf="registration.get('userInfoUri').hasError('pattern')">  
165 - {{ 'admin.oauth2.uri-pattern-error' | translate }}  
166 - </mat-error>  
167 - </mat-form-field>  
168 - </div>  
169 -  
170 - <mat-form-field fxFlex class="mat-block">  
171 - <mat-label translate>admin.oauth2.client-authentication-method</mat-label>  
172 - <mat-select formControlName="clientAuthenticationMethod">  
173 - <mat-option *ngFor="let clientAuthenticationMethod of clientAuthenticationMethods"  
174 - [value]="clientAuthenticationMethod">  
175 - {{ clientAuthenticationMethod | uppercase }}  
176 - </mat-option>  
177 - </mat-select>  
178 - </mat-form-field>  
179 -  
180 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" *ngIf="registration.get('providerName').value === 'Custom'">  
181 - <mat-form-field fxFlex class="mat-block">  
182 - <mat-label translate>admin.oauth2.login-button-label</mat-label>  
183 - <input matInput formControlName="loginButtonLabel" required>  
184 - <mat-error  
185 - *ngIf="registration.get('loginButtonLabel').hasError('required')">  
186 - {{ 'admin.oauth2.login-button-label-required' | translate }}  
187 - </mat-error>  
188 - </mat-form-field>  
189 -  
190 - <mat-form-field fxFlex class="mat-block">  
191 - <mat-label translate>admin.oauth2.login-button-icon</mat-label>  
192 - <input matInput formControlName="loginButtonIcon">  
193 - </mat-form-field>  
194 - </div>  
195 -  
196 - <mat-form-field fxFlex class="mat-block">  
197 - <mat-label translate>admin.oauth2.scope</mat-label>  
198 - <mat-chip-list #scopeList>  
199 - <mat-chip *ngFor="let scope of registration.get('scope').value; let k = index;"  
200 - removable (removed)="removeScope(k, registration)">  
201 - {{scope}}  
202 - <mat-icon matChipRemove>cancel</mat-icon>  
203 - </mat-chip>  
204 - <input [matChipInputFor]="scopeList"  
205 - [matChipInputSeparatorKeyCodes]="separatorKeysCodes"  
206 - matChipInputAddOnBlur  
207 - (matChipInputTokenEnd)="addScope($event, registration)">  
208 - </mat-chip-list>  
209 - <mat-error *ngIf="registration.get('scope').hasError('required')">  
210 - {{ 'admin.oauth2.jwk-set-uri-required' | translate }}  
211 - </mat-error>  
212 - </mat-form-field>  
213 -  
214 - </mat-tab>  
215 - <mat-tab label="Mapper">  
216 - <mat-form-field class="mat-block" style="margin-top: 16px;">  
217 - <mat-label translate>admin.oauth2.user-name-attribute-name</mat-label>  
218 - <input matInput formControlName="userNameAttributeName" required>  
219 - <mat-error *ngIf="registration.get('userNameAttributeName').hasError('required')">  
220 - {{ 'admin.oauth2.user-name-attribute-name-required' | translate }}  
221 - </mat-error>  
222 - </mat-form-field>  
223 -  
224 - <section formGroupName="mapperConfig">  
225 - <div fxLayout="column" fxLayoutGap="8px">  
226 - <mat-checkbox formControlName="allowUserCreation">  
227 - {{ 'admin.oauth2.allow-user-creation' | translate }}  
228 - </mat-checkbox>  
229 - <mat-checkbox formControlName="activateUser">  
230 - {{ 'admin.oauth2.activate-user' | translate }}  
231 - </mat-checkbox>  
232 - </div>  
233 -  
234 - <mat-form-field fxFlex class="mat-block">  
235 - <mat-label translate>admin.oauth2.type</mat-label>  
236 - <mat-select formControlName="type">  
237 - <mat-option *ngFor="let converterTypeExternalUser of converterTypesExternalUser"  
238 - [value]="converterTypeExternalUser">  
239 - {{ converterTypeExternalUser }}  
240 - </mat-option>  
241 - </mat-select>  
242 - </mat-form-field>  
243 -  
244 - <section formGroupName="basic"  
245 - *ngIf="registration.get('mapperConfig.type').value === 'BASIC'">  
246 - <mat-form-field class="mat-block">  
247 - <mat-label translate>admin.oauth2.email-attribute-key</mat-label>  
248 - <input matInput formControlName="emailAttributeKey" required>  
249 - <mat-error  
250 - *ngIf="registration.get('mapperConfig.basic.emailAttributeKey').hasError('required')">  
251 - {{ 'admin.oauth2.email-attribute-key-required' | translate }}  
252 - </mat-error>  
253 - </mat-form-field>  
254 -  
255 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px"> 120 + <mat-expansion-panel class="mat-elevation-z0 custom-settings"
  121 + [disabled]="registration.get('providerName').value === 'Custom'"
  122 + [expanded]="registration.get('providerName').value === 'Custom'">
  123 + <mat-expansion-panel-header [fxHide]="registration.get('providerName').value === 'Custom'">
  124 + <mat-panel-description fxLayoutAlign="end center">
  125 + {{ 'admin.oauth2.custom-setting' | translate }}
  126 + </mat-panel-description>
  127 + </mat-expansion-panel-header>
  128 + <ng-template matExpansionPanelContent>
  129 + <mat-tab-group dynamicHeight>
  130 + <mat-tab label="{{ 'admin.oauth2.general' | translate }}">
  131 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" style="margin-top: 16px;">
256 <mat-form-field fxFlex class="mat-block"> 132 <mat-form-field fxFlex class="mat-block">
257 - <mat-label translate>admin.oauth2.first-name-attribute-key</mat-label>  
258 - <input matInput formControlName="firstNameAttributeKey"> 133 + <mat-label translate>admin.oauth2.access-token-uri</mat-label>
  134 + <input matInput formControlName="accessTokenUri" required>
  135 + <button mat-icon-button matSuffix
  136 + type="button"
  137 + (click)="toggleEditMode(registration, 'accessTokenUri')"
  138 + *ngIf="registration.get('providerName').value !== 'Custom'">
  139 + <mat-icon class="material-icons">create</mat-icon>
  140 + </button>
  141 + <mat-error *ngIf="registration.get('accessTokenUri').hasError('required')">
  142 + {{ 'admin.oauth2.access-token-uri-required' | translate }}
  143 + </mat-error>
  144 + <mat-error *ngIf="registration.get('accessTokenUri').hasError('pattern')">
  145 + {{ 'admin.oauth2.uri-pattern-error' | translate }}
  146 + </mat-error>
259 </mat-form-field> 147 </mat-form-field>
260 148
261 <mat-form-field fxFlex class="mat-block"> 149 <mat-form-field fxFlex class="mat-block">
262 - <mat-label translate>admin.oauth2.last-name-attribute-key</mat-label>  
263 - <input matInput formControlName="lastNameAttributeKey"> 150 + <mat-label translate>admin.oauth2.authorization-uri</mat-label>
  151 + <input matInput formControlName="authorizationUri" required>
  152 + <button mat-icon-button matSuffix
  153 + type="button"
  154 + (click)="toggleEditMode(registration, 'authorizationUri')"
  155 + *ngIf="registration.get('providerName').value !== 'Custom'">
  156 + <mat-icon class="material-icons">create</mat-icon>
  157 + </button>
  158 + <mat-error *ngIf="registration.get('authorizationUri').hasError('required')">
  159 + {{ 'admin.oauth2.authorization-uri-required' | translate }}
  160 + </mat-error>
  161 + <mat-error *ngIf="registration.get('authorizationUri').hasError('pattern')">
  162 + {{ 'admin.oauth2.uri-pattern-error' | translate }}
  163 + </mat-error>
264 </mat-form-field> 164 </mat-form-field>
265 </div> 165 </div>
266 166
267 <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px"> 167 <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
268 - <mat-form-field fxFlex class="mat-block">  
269 - <mat-label translate>admin.oauth2.tenant-name-strategy</mat-label>  
270 - <mat-select formControlName="tenantNameStrategy">  
271 - <mat-option *ngFor="let tenantNameStrategy of tenantNameStrategies"  
272 - [value]="tenantNameStrategy">  
273 - {{ tenantNameStrategy }}  
274 - </mat-option>  
275 - </mat-select> 168 + <mat-form-field fxFlex class="mat-block" appearance="legacy">
  169 + <mat-label translate>admin.oauth2.jwk-set-uri</mat-label>
  170 + <input matInput formControlName="jwkSetUri">
  171 + <button mat-icon-button matSuffix
  172 + type="button" aria-label="Clear"
  173 + (click)="toggleEditMode(registration, 'jwkSetUri')"
  174 + *ngIf="registration.get('providerName').value !== 'Custom'">
  175 + <mat-icon class="material-icons">create</mat-icon>
  176 + </button>
  177 + <mat-error *ngIf="registration.get('jwkSetUri').hasError('pattern')">
  178 + {{ 'admin.oauth2.uri-pattern-error' | translate }}
  179 + </mat-error>
276 </mat-form-field> 180 </mat-form-field>
277 181
278 - <mat-form-field fxFlex class="mat-block" *ngIf="registration.get('mapperConfig.basic.tenantNameStrategy').value === 'CUSTOM'">  
279 - <mat-label translate>admin.oauth2.tenant-name-pattern</mat-label>  
280 - <input matInput  
281 - formControlName="tenantNamePattern"  
282 - [required]="registration.get('mapperConfig.basic.tenantNameStrategy').value === 'CUSTOM'">  
283 - <mat-error  
284 - *ngIf="registration.get('mapperConfig.basic.tenantNamePattern').hasError('required')">  
285 - {{ 'admin.oauth2.tenant-name-pattern-required' | translate }} 182 + <mat-form-field fxFlex class="mat-block">
  183 + <mat-label translate>admin.oauth2.user-info-uri</mat-label>
  184 + <input matInput formControlName="userInfoUri" required>
  185 + <button mat-icon-button matSuffix
  186 + type="button"
  187 + (click)="toggleEditMode(registration, 'userInfoUri')"
  188 + *ngIf="registration.get('providerName').value !== 'Custom'">
  189 + <mat-icon class="material-icons">create</mat-icon>
  190 + </button>
  191 + <mat-error *ngIf="registration.get('userInfoUri').hasError('required')">
  192 + {{ 'admin.oauth2.user-info-uri-required' | translate }}
  193 + </mat-error>
  194 + <mat-error *ngIf="registration.get('userInfoUri').hasError('pattern')">
  195 + {{ 'admin.oauth2.uri-pattern-error' | translate }}
286 </mat-error> 196 </mat-error>
287 </mat-form-field> 197 </mat-form-field>
288 </div> 198 </div>
289 199
290 <mat-form-field fxFlex class="mat-block"> 200 <mat-form-field fxFlex class="mat-block">
291 - <mat-label translate>admin.oauth2.customer-name-pattern</mat-label>  
292 - <input matInput formControlName="customerNamePattern"> 201 + <mat-label translate>admin.oauth2.client-authentication-method</mat-label>
  202 + <mat-select formControlName="clientAuthenticationMethod">
  203 + <mat-option *ngFor="let clientAuthenticationMethod of clientAuthenticationMethods"
  204 + [value]="clientAuthenticationMethod">
  205 + {{ clientAuthenticationMethod | uppercase }}
  206 + </mat-option>
  207 + </mat-select>
293 </mat-form-field> 208 </mat-form-field>
294 209
295 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px"> 210 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px" *ngIf="registration.get('providerName').value === 'Custom'">
296 <mat-form-field fxFlex class="mat-block"> 211 <mat-form-field fxFlex class="mat-block">
297 - <mat-label translate>admin.oauth2.default-dashboard-name</mat-label>  
298 - <input matInput formControlName="defaultDashboardName"> 212 + <mat-label translate>admin.oauth2.login-button-label</mat-label>
  213 + <input matInput formControlName="loginButtonLabel" required>
  214 + <mat-error
  215 + *ngIf="registration.get('loginButtonLabel').hasError('required')">
  216 + {{ 'admin.oauth2.login-button-label-required' | translate }}
  217 + </mat-error>
299 </mat-form-field> 218 </mat-form-field>
300 219
301 - <mat-checkbox fxFlex formControlName="alwaysFullScreen" class="checkbox-row">  
302 - {{ 'admin.oauth2.always-fullscreen' | translate}}  
303 - </mat-checkbox> 220 + <mat-form-field fxFlex class="mat-block">
  221 + <mat-label translate>admin.oauth2.login-button-icon</mat-label>
  222 + <input matInput formControlName="loginButtonIcon">
  223 + </mat-form-field>
304 </div> 224 </div>
305 - </section>  
306 -  
307 - <section formGroupName="custom"  
308 - *ngIf="registration.get('mapperConfig.type').value === 'CUSTOM'">  
309 - <mat-form-field class="mat-block">  
310 - <mat-label translate>admin.oauth2.url</mat-label>  
311 - <input matInput formControlName="url" required>  
312 - <mat-error  
313 - *ngIf="registration.get('mapperConfig.custom.url').hasError('required')">  
314 - {{ 'admin.oauth2.url-required' | translate }}  
315 - </mat-error>  
316 - <mat-error  
317 - *ngIf="registration.get('mapperConfig.custom.url').hasError('pattern')">  
318 - {{ 'admin.oauth2.url-pattern' | translate }} 225 +
  226 + <section formGroupName="mapperConfig">
  227 + <div fxLayout="column" fxLayoutGap="8px" style="margin-bottom: 8px;">
  228 + <mat-checkbox formControlName="allowUserCreation">
  229 + {{ 'admin.oauth2.allow-user-creation' | translate }}
  230 + </mat-checkbox>
  231 + <mat-checkbox formControlName="activateUser">
  232 + {{ 'admin.oauth2.activate-user' | translate }}
  233 + </mat-checkbox>
  234 + </div>
  235 + </section>
  236 +
  237 + <mat-form-field fxFlex class="mat-block">
  238 + <mat-label translate>admin.oauth2.scope</mat-label>
  239 + <mat-chip-list #scopeList>
  240 + <mat-chip *ngFor="let scope of registration.get('scope').value; let k = index;"
  241 + removable (removed)="removeScope(k, registration)">
  242 + {{scope}}
  243 + <mat-icon matChipRemove>cancel</mat-icon>
  244 + </mat-chip>
  245 + <input [matChipInputFor]="scopeList"
  246 + [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
  247 + matChipInputAddOnBlur
  248 + (matChipInputTokenEnd)="addScope($event, registration)">
  249 + </mat-chip-list>
  250 + </mat-form-field>
  251 +
  252 + </mat-tab>
  253 + <mat-tab label="{{ 'admin.oauth2.mapper' | translate }}">
  254 + <mat-form-field class="mat-block" style="margin-top: 16px;">
  255 + <mat-label translate>admin.oauth2.user-name-attribute-name</mat-label>
  256 + <input matInput formControlName="userNameAttributeName" required>
  257 + <mat-error *ngIf="registration.get('userNameAttributeName').hasError('required')">
  258 + {{ 'admin.oauth2.user-name-attribute-name-required' | translate }}
319 </mat-error> 259 </mat-error>
320 </mat-form-field> 260 </mat-form-field>
321 261
322 - <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px"> 262 + <section formGroupName="mapperConfig">
323 <mat-form-field fxFlex class="mat-block"> 263 <mat-form-field fxFlex class="mat-block">
324 - <mat-label translate>common.username</mat-label>  
325 - <input matInput formControlName="username" autocomplete="new-username"> 264 + <mat-label translate>admin.oauth2.type</mat-label>
  265 + <mat-select formControlName="type">
  266 + <mat-option *ngFor="let converterTypeExternalUser of converterTypesExternalUser"
  267 + [value]="converterTypeExternalUser">
  268 + {{ converterTypeExternalUser }}
  269 + </mat-option>
  270 + </mat-select>
326 </mat-form-field> 271 </mat-form-field>
327 272
328 - <mat-form-field fxFlex class="mat-block">  
329 - <mat-label translate>common.password</mat-label>  
330 - <input matInput type="password" formControlName="password" autocomplete="new-password">  
331 - </mat-form-field>  
332 - </div>  
333 - </section>  
334 - </section>  
335 - </mat-tab>  
336 - </mat-tab-group> 273 + <section formGroupName="basic"
  274 + *ngIf="registration.get('mapperConfig.type').value === 'BASIC'">
  275 + <mat-form-field class="mat-block">
  276 + <mat-label translate>admin.oauth2.email-attribute-key</mat-label>
  277 + <input matInput formControlName="emailAttributeKey" required>
  278 + <mat-error
  279 + *ngIf="registration.get('mapperConfig.basic.emailAttributeKey').hasError('required')">
  280 + {{ 'admin.oauth2.email-attribute-key-required' | translate }}
  281 + </mat-error>
  282 + </mat-form-field>
  283 +
  284 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
  285 + <mat-form-field fxFlex class="mat-block">
  286 + <mat-label translate>admin.oauth2.first-name-attribute-key</mat-label>
  287 + <input matInput formControlName="firstNameAttributeKey">
  288 + </mat-form-field>
  289 +
  290 + <mat-form-field fxFlex class="mat-block">
  291 + <mat-label translate>admin.oauth2.last-name-attribute-key</mat-label>
  292 + <input matInput formControlName="lastNameAttributeKey">
  293 + </mat-form-field>
  294 + </div>
  295 +
  296 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
  297 + <mat-form-field fxFlex class="mat-block">
  298 + <mat-label translate>admin.oauth2.tenant-name-strategy</mat-label>
  299 + <mat-select formControlName="tenantNameStrategy">
  300 + <mat-option *ngFor="let tenantNameStrategy of tenantNameStrategies"
  301 + [value]="tenantNameStrategy">
  302 + {{ tenantNameStrategy }}
  303 + </mat-option>
  304 + </mat-select>
  305 + </mat-form-field>
  306 +
  307 + <mat-form-field fxFlex class="mat-block" *ngIf="registration.get('mapperConfig.basic.tenantNameStrategy').value === 'CUSTOM'">
  308 + <mat-label translate>admin.oauth2.tenant-name-pattern</mat-label>
  309 + <input matInput
  310 + formControlName="tenantNamePattern"
  311 + [required]="registration.get('mapperConfig.basic.tenantNameStrategy').value === 'CUSTOM'">
  312 + <mat-error
  313 + *ngIf="registration.get('mapperConfig.basic.tenantNamePattern').hasError('required')">
  314 + {{ 'admin.oauth2.tenant-name-pattern-required' | translate }}
  315 + </mat-error>
  316 + </mat-form-field>
  317 + </div>
  318 +
  319 + <mat-form-field fxFlex class="mat-block">
  320 + <mat-label translate>admin.oauth2.customer-name-pattern</mat-label>
  321 + <input matInput formControlName="customerNamePattern">
  322 + </mat-form-field>
  323 +
  324 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
  325 + <mat-form-field fxFlex class="mat-block">
  326 + <mat-label translate>admin.oauth2.default-dashboard-name</mat-label>
  327 + <input matInput formControlName="defaultDashboardName">
  328 + </mat-form-field>
  329 +
  330 + <mat-checkbox fxFlex formControlName="alwaysFullScreen" class="checkbox-row">
  331 + {{ 'admin.oauth2.always-fullscreen' | translate}}
  332 + </mat-checkbox>
  333 + </div>
  334 + </section>
  335 +
  336 + <section formGroupName="custom"
  337 + *ngIf="registration.get('mapperConfig.type').value === 'CUSTOM'">
  338 + <mat-form-field class="mat-block">
  339 + <mat-label translate>admin.oauth2.url</mat-label>
  340 + <input matInput formControlName="url" required>
  341 + <mat-error
  342 + *ngIf="registration.get('mapperConfig.custom.url').hasError('required')">
  343 + {{ 'admin.oauth2.url-required' | translate }}
  344 + </mat-error>
  345 + <mat-error
  346 + *ngIf="registration.get('mapperConfig.custom.url').hasError('pattern')">
  347 + {{ 'admin.oauth2.url-pattern' | translate }}
  348 + </mat-error>
  349 + </mat-form-field>
  350 +
  351 + <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
  352 + <mat-form-field fxFlex class="mat-block">
  353 + <mat-label translate>common.username</mat-label>
  354 + <input matInput formControlName="username" autocomplete="new-username">
  355 + </mat-form-field>
  356 +
  357 + <mat-form-field fxFlex class="mat-block">
  358 + <mat-label translate>common.password</mat-label>
  359 + <input matInput type="password" formControlName="password" autocomplete="new-password">
  360 + </mat-form-field>
  361 + </div>
  362 + </section>
  363 + </section>
  364 + </mat-tab>
  365 + </mat-tab-group>
  366 + </ng-template>
  367 + </mat-expansion-panel>
337 368
338 </section> 369 </section>
339 </ng-template> 370 </ng-template>
@@ -21,9 +21,32 @@ @@ -21,9 +21,32 @@
21 .registration-card{ 21 .registration-card{
22 margin-bottom: 8px; 22 margin-bottom: 8px;
23 border: 1px solid rgba(0, 0, 0, 0.2); 23 border: 1px solid rgba(0, 0, 0, 0.2);
  24 +
  25 + .custom-settings{
  26 + font-size: 16px;
  27 + .mat-expansion-panel-header{
  28 + padding: 0 2px;
  29 + }
  30 + }
24 } 31 }
25 32
26 .container{ 33 .container{
27 margin-bottom: 16px; 34 margin-bottom: 16px;
28 } 35 }
29 } 36 }
  37 +
  38 +:host ::ng-deep{
  39 + .registration-card{
  40 + .custom-settings{
  41 + .mat-expansion-panel-body{
  42 + padding: 0 2px 16px;
  43 + }
  44 + .mat-tab-label{
  45 + text-transform: none;
  46 + }
  47 + .mat-form-field-suffix .mat-icon-button .mat-icon{
  48 + font-size: 18px;
  49 + }
  50 + }
  51 + }
  52 +}
@@ -18,6 +18,7 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, ViewContainerR @@ -18,6 +18,7 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit, ViewContainerR
18 import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; 18 import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
19 import { 19 import {
20 ClientAuthenticationMethod, 20 ClientAuthenticationMethod,
  21 + ClientProviderTemplated,
21 ClientRegistration, 22 ClientRegistration,
22 DomainParams, 23 DomainParams,
23 MapperConfigType, 24 MapperConfigType,
@@ -50,9 +51,24 @@ import { @@ -50,9 +51,24 @@ import {
50 }) 51 })
51 export class OAuth2SettingsComponent extends PageComponent implements OnInit, HasConfirmForm, OnDestroy { 52 export class OAuth2SettingsComponent extends PageComponent implements OnInit, HasConfirmForm, OnDestroy {
52 53
53 - private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/; 54 + private URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.,?+=&%@\-/]*)?$/;
54 private subscriptions: Subscription[] = []; 55 private subscriptions: Subscription[] = [];
55 - private templates = []; 56 + private templates = new Map<string, ClientProviderTemplated>();
  57 + private defaultProvider = {
  58 + providerName: 'Custom',
  59 + clientAuthenticationMethod: 'Post',
  60 + userNameAttributeName: 'email',
  61 + mapperConfig: {
  62 + allowUserCreation: true,
  63 + activateUser: false,
  64 + type: 'BASIC',
  65 + basic: {
  66 + emailAttributeKey: 'email',
  67 + tenantNameStrategy: 'DOMAIN',
  68 + alwaysFullScreen: false
  69 + }
  70 + }
  71 + };
56 72
57 readonly separatorKeysCodes: number[] = [ENTER, COMMA]; 73 readonly separatorKeysCodes: number[] = [ENTER, COMMA];
58 74
@@ -99,9 +115,9 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha @@ -99,9 +115,9 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
99 }); 115 });
100 } 116 }
101 117
102 - private initTemplates(templates: any): void {  
103 - this.templates = templates;  
104 - templates.map(provider => this.templateProvider.push(provider.name)); 118 + private initTemplates(templates: ClientProviderTemplated[]): void {
  119 + templates.map(provider => this.templates.set(provider.name, provider));
  120 + this.templateProvider.push(...Array.from(this.templates.keys()));
105 this.templateProvider.sort(); 121 this.templateProvider.sort();
106 } 122 }
107 123
@@ -118,7 +134,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha @@ -118,7 +134,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
118 tenantNamePattern: [null], 134 tenantNamePattern: [null],
119 customerNamePattern: [null], 135 customerNamePattern: [null],
120 defaultDashboardName: [null], 136 defaultDashboardName: [null],
121 - alwaysFullScreen: [false], 137 + alwaysFullScreen: [false]
122 }); 138 });
123 139
124 this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => { 140 this.subscriptions.push(basicGroup.get('tenantNameStrategy').valueChanges.subscribe((domain) => {
@@ -209,7 +225,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha @@ -209,7 +225,7 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
209 accessTokenUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], 225 accessTokenUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]],
210 authorizationUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], 226 authorizationUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]],
211 scope: this.fb.array([], [Validators.required]), 227 scope: this.fb.array([], [Validators.required]),
212 - jwkSetUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], 228 + jwkSetUri: ['', [Validators.pattern(this.URL_REGEXP)]],
213 userInfoUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]], 229 userInfoUri: ['', [Validators.required, Validators.pattern(this.URL_REGEXP)]],
214 clientAuthenticationMethod: ['POST', [Validators.required]], 230 clientAuthenticationMethod: ['POST', [Validators.required]],
215 userNameAttributeName: ['email', [Validators.required]], 231 userNameAttributeName: ['email', [Validators.required]],
@@ -233,6 +249,27 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha @@ -233,6 +249,27 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
233 } 249 }
234 })); 250 }));
235 251
  252 + this.subscriptions.push(clientRegistration.get('providerName').valueChanges.subscribe((provider) => {
  253 + (clientRegistration.get('scope') as FormArray).clear();
  254 + if (provider === 'Custom') {
  255 + clientRegistration.reset(this.defaultProvider, {emitEvent: false});
  256 + clientRegistration.get('accessTokenUri').enable();
  257 + clientRegistration.get('authorizationUri').enable();
  258 + clientRegistration.get('jwkSetUri').enable();
  259 + clientRegistration.get('userInfoUri').enable();
  260 + } else {
  261 + const template = this.templates.get(provider);
  262 + template.scope.forEach(() => {
  263 + (clientRegistration.get('scope') as FormArray).push(this.fb.control(''));
  264 + });
  265 + clientRegistration.get('accessTokenUri').disable();
  266 + clientRegistration.get('authorizationUri').disable();
  267 + clientRegistration.get('jwkSetUri').disable();
  268 + clientRegistration.get('userInfoUri').disable();
  269 + clientRegistration.patchValue(this.templates.get(provider), {emitEvent: false});
  270 + }
  271 + }));
  272 +
236 if (registrationData) { 273 if (registrationData) {
237 registrationData.scope.forEach(() => { 274 registrationData.scope.forEach(() => {
238 (clientRegistration.get('scope') as FormArray).push(this.fb.control('')); 275 (clientRegistration.get('scope') as FormArray).push(this.fb.control(''));
@@ -366,4 +403,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha @@ -366,4 +403,8 @@ export class OAuth2SettingsComponent extends PageComponent implements OnInit, Ha
366 } 403 }
367 }); 404 });
368 } 405 }
  406 +
  407 + toggleEditMode(control: AbstractControl, path: string) {
  408 + control.get(path).disabled ? control.get(path).enable() : control.get(path).disable();
  409 + }
369 } 410 }
@@ -14,6 +14,9 @@ @@ -14,6 +14,9 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
  17 +import { EntityId } from '@shared/models/id/entity-id';
  18 +import { TenantId } from '@shared/models/id/tenant-id';
  19 +
17 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])$/; 20 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])$/;
18 21
19 export interface AdminSettings<T> { 22 export interface AdminSettings<T> {
@@ -75,6 +78,17 @@ export interface DomainParams { @@ -75,6 +78,17 @@ export interface DomainParams {
75 clientRegistrations: ClientRegistration[]; 78 clientRegistrations: ClientRegistration[];
76 } 79 }
77 80
  81 +export interface ClientProviderTemplated extends ClientRegistration{
  82 + additionalInfo: string;
  83 + comment: string;
  84 + createdTime: number;
  85 + helpLink: string;
  86 + id: EntityId;
  87 + name: string;
  88 + providerId: string;
  89 + tenantId: TenantId;
  90 +}
  91 +
78 export interface ClientRegistration { 92 export interface ClientRegistration {
79 loginButtonLabel: string; 93 loginButtonLabel: string;
80 loginButtonIcon: string; 94 loginButtonIcon: string;
@@ -128,7 +128,7 @@ @@ -128,7 +128,7 @@
128 "add-provider": "Add provider", 128 "add-provider": "Add provider",
129 "settings": "Settings", 129 "settings": "Settings",
130 "oauth2": { 130 "oauth2": {
131 - "settings": "OAuth2 Settings", 131 + "oauth2": "OAuth2",
132 "registration-id": "Registration ID", 132 "registration-id": "Registration ID",
133 "registration-id-required": "Registration ID is required.", 133 "registration-id-required": "Registration ID is required.",
134 "registration-id-unique": "Registration ID need to unique for the system.", 134 "registration-id-unique": "Registration ID need to unique for the system.",
@@ -145,7 +145,6 @@ @@ -145,7 +145,6 @@
145 "redirect-uri-template": "Redirect URI template", 145 "redirect-uri-template": "Redirect URI template",
146 "redirect-uri-template-required": "Redirect URI template is required.", 146 "redirect-uri-template-required": "Redirect URI template is required.",
147 "jwk-set-uri": "JSON Web Key URI", 147 "jwk-set-uri": "JSON Web Key URI",
148 - "jwk-set-uri-required": "JSON Web Key URI is required.",  
149 "user-info-uri": "User info URI", 148 "user-info-uri": "User info URI",
150 "user-info-uri-required": "User info URI is required.", 149 "user-info-uri-required": "User info URI is required.",
151 "client-authentication-method": "Client authentication method", 150 "client-authentication-method": "Client authentication method",
@@ -173,7 +172,11 @@ @@ -173,7 +172,11 @@
173 "delete-domain-title": "Are you sure you want to delete the domain '{{domainName}}'?", 172 "delete-domain-title": "Are you sure you want to delete the domain '{{domainName}}'?",
174 "delete-domain-text": "Be careful, after the confirmation a domain and all registration data will be unavailable.", 173 "delete-domain-text": "Be careful, after the confirmation a domain and all registration data will be unavailable.",
175 "delete-registration-title": "Are you sure you want to delete the registration '{{name}}'?", 174 "delete-registration-title": "Are you sure you want to delete the registration '{{name}}'?",
176 - "delete-registration-text": "Be careful, after the confirmation a registration data will be unavailable." 175 + "delete-registration-text": "Be careful, after the confirmation a registration data will be unavailable.",
  176 + "login-provider": "Login provider",
  177 + "custom-setting": "Custom settings",
  178 + "general": "General",
  179 + "mapper": "Mapper"
177 } 180 }
178 }, 181 },
179 "alarm": { 182 "alarm": {