feat(console): add SAML certificate link and endpoints (#6841)

* feat(console): add SAML certificate link and endpoints

* fix: add missing translations for cs and ru

* fix: add @eliobischof review suggestions

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
Miguel Cabrerizo 2023-11-13 18:49:55 +01:00 committed by GitHub
parent 081a0b4cb7
commit bd63fcd15d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 138 additions and 5 deletions

View File

@ -381,6 +381,19 @@
</span> </span>
</span> </span>
</div> </div>
<div class="row">
<span class="left cnsl-secondary-text">
{{ 'APP.SAML.CERTIFICATE' | translate }}
</span>
<a
*ngIf="samlCertificateURL$ | async as samlCertificateURL"
href="{{ samlCertificateURL }}"
class="cert"
rel="noreferrer"
download
>{{ 'APP.SAML.DOWNLOADCERT' | translate }}</a
>
</div>
</ng-container> </ng-container>
<div class="app-create-actions"> <div class="app-create-actions">

View File

@ -161,3 +161,15 @@ p.desc {
font-size: 14px; font-size: 14px;
} }
} }
.cert {
font-size: 14px;
cursor: pointer;
text-decoration: none;
color: inherit;
font-family: inherit;
&:hover {
text-decoration: underline;
}
}

View File

@ -7,7 +7,7 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router'; import { ActivatedRoute, Params, Router } from '@angular/router';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import { Subject, Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, map, takeUntil } from 'rxjs/operators';
import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component'; import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component';
import { requiredValidator } from 'src/app/modules/form-field/validators/validators'; import { requiredValidator } from 'src/app/modules/form-field/validators/validators';
import { import {
@ -28,7 +28,6 @@ import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/
import { ManagementService } from 'src/app/services/mgmt.service'; import { ManagementService } from 'src/app/services/mgmt.service';
import { ToastService } from 'src/app/services/toast.service'; import { ToastService } from 'src/app/services/toast.service';
import { MatLegacySlideToggleChange } from '@angular/material/legacy-slide-toggle';
import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component'; import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component';
import { import {
BASIC_AUTH_METHOD, BASIC_AUTH_METHOD,
@ -41,6 +40,7 @@ import {
POST_METHOD, POST_METHOD,
} from '../authmethods'; } from '../authmethods';
import { API_TYPE, AppCreateType, NATIVE_TYPE, RadioItemAppType, SAML_TYPE, USER_AGENT_TYPE, WEB_TYPE } from '../authtypes'; import { API_TYPE, AppCreateType, NATIVE_TYPE, RadioItemAppType, SAML_TYPE, USER_AGENT_TYPE, WEB_TYPE } from '../authtypes';
import { EnvironmentService } from 'src/app/services/environment.service';
const MAX_ALLOWED_SIZE = 1 * 1024 * 1024; const MAX_ALLOWED_SIZE = 1 * 1024 * 1024;
@ -119,6 +119,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
public requestRedirectValuesSubject$: Subject<void> = new Subject(); public requestRedirectValuesSubject$: Subject<void> = new Subject();
public samlCertificateURL$ = this.envSvc.env.pipe(map((env) => `${env.issuer}/saml/v2/certificate`));
constructor( constructor(
private router: Router, private router: Router,
@ -129,6 +130,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
private fb: UntypedFormBuilder, private fb: UntypedFormBuilder,
private _location: Location, private _location: Location,
private breadcrumbService: BreadcrumbService, private breadcrumbService: BreadcrumbService,
private envSvc: EnvironmentService,
) { ) {
this.form = this.fb.group({ this.form = this.fb.group({
name: ['', [requiredValidator]], name: ['', [requiredValidator]],

View File

@ -414,10 +414,11 @@
</cnsl-card> </cnsl-card>
</ng-container> </ng-container>
<ng-container *ngIf="currentSetting === 'urls'"> <ng-container *ngIf="currentSetting === 'urls' && !app?.samlConfig">
<cnsl-card title=" {{ 'APP.URLS' | translate }}" *ngIf="environmentMap$ | async as environmentMap"> <cnsl-card title=" {{ 'APP.URLS' | translate }}" *ngIf="environmentMap$ | async as environmentMap">
<cnsl-info-section *ngIf="environmentMap.issuer"> <cnsl-info-section *ngIf="environmentMap.issuer">
<div <div
class="link"
[innerHtml]=" [innerHtml]="
'APP.OIDC.WELLKNOWN' | translate: { url: environmentMap['issuer'] + '/.well-known/openid-configuration' } 'APP.OIDC.WELLKNOWN' | translate: { url: environmentMap['issuer'] + '/.well-known/openid-configuration' }
" "
@ -466,6 +467,65 @@
</cnsl-card> </cnsl-card>
</ng-container> </ng-container>
<ng-container *ngIf="currentSetting === 'urls' && samlForm && app?.samlConfig">
<cnsl-card title=" {{ 'APP.URLS' | translate }}" *ngIf="environmentMap$ | async as environmentMap">
<div class="app-info-row">
<div class="app-info-wrapper" *ngIf="environmentMap['samlCertificateURL']">
<p class="app-info-row-title cnsl-secondary-text">{{ 'APP.SAML.CERTIFICATE' | translate }}</p>
<div class="app-copy-row">
<div class="environment">
<button
[disabled]="copied === environmentMap['samlCertificateURL']"
[matTooltip]="
(copied !== environmentMap['samlCertificateURL'] ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate
"
cnslCopyToClipboard
[valueToCopy]="environmentMap['samlCertificateURL']"
(copiedValue)="copied = environmentMap['samlCertificateURL']"
>
{{ environmentMap['samlCertificateURL'] }}
</button>
</div>
</div>
</div>
<div class="app-info-wrapper" *ngIf="environmentMap['samlSSO']">
<p class="app-info-row-title cnsl-secondary-text">Single Sign On (SSO)</p>
<div class="app-copy-row">
<div class="environment">
<button
[disabled]="copied === environmentMap['samlSSO']"
[matTooltip]="(copied !== environmentMap['samlSSO'] ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="environmentMap['samlSSO']"
(copiedValue)="copied = environmentMap['samlSSO']"
>
{{ environmentMap['samlSSO'] }}
</button>
</div>
</div>
</div>
<div class="app-info-wrapper" *ngIf="environmentMap['samlSLO']">
<p class="app-info-row-title cnsl-secondary-text">Single Logoout (SLO)</p>
<div class="app-copy-row">
<div class="environment">
<button
[disabled]="copied === environmentMap['samlSLO']"
[matTooltip]="(copied !== environmentMap['samlSLO'] ? 'ACTIONS.COPY' : 'ACTIONS.COPIED') | translate"
cnslCopyToClipboard
[valueToCopy]="environmentMap['samlSLO']"
(copiedValue)="copied = environmentMap['samlSLO']"
>
{{ environmentMap['samlSLO'] }}
</button>
</div>
</div>
</div>
</div>
</cnsl-card>
</ng-container>
<ng-container *ngIf="currentSetting === 'configuration'"> <ng-container *ngIf="currentSetting === 'configuration'">
<cnsl-card <cnsl-card
*ngIf="initialAuthMethod === 'PK_JWT' && projectId && app && app.id" *ngIf="initialAuthMethod === 'PK_JWT' && projectId && app && app.id"

View File

@ -288,3 +288,14 @@
justify-content: flex-end; justify-content: flex-end;
margin-top: 1rem; margin-top: 1rem;
} }
.link a {
cursor: pointer;
text-decoration: none;
color: inherit;
font-family: inherit;
&:hover {
text-decoration: underline;
}
}

View File

@ -86,6 +86,9 @@ export class AppDetailComponent implements OnInit, OnDestroy {
adminServiceUrl: `${env.api}/admin/v1`, adminServiceUrl: `${env.api}/admin/v1`,
mgmtServiceUrl: `${env.api}/management/v1`, mgmtServiceUrl: `${env.api}/management/v1`,
authServiceUrl: `${env.api}/auth/v1`, authServiceUrl: `${env.api}/auth/v1`,
samlCertificateURL: `${env.issuer}/saml/v2/certificate`,
samlSSO: `${env.issuer}/saml/v2/SSO`,
samlSLO: `${env.issuer}/saml/v2/SLO`,
}; };
}), }),
); );
@ -351,7 +354,10 @@ export class AppDetailComponent implements OnInit, OnDestroy {
this.authMethods = this.authMethods.filter((element) => element !== CUSTOM_METHOD); this.authMethods = this.authMethods.filter((element) => element !== CUSTOM_METHOD);
} }
} else if (this.app.samlConfig) { } else if (this.app.samlConfig) {
this.settingsList = [{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' }]; this.settingsList = [
{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' },
{ id: 'urls', i18nKey: 'APP.URLS' },
];
} }
if (allowed) { if (allowed) {

View File

@ -2086,6 +2086,8 @@
"UPLOAD": "Качете XML файл", "UPLOAD": "Качете XML файл",
"METADATA": "Метаданни", "METADATA": "Метаданни",
"METADATAFROMFILE": "Метаданни от файл", "METADATAFROMFILE": "Метаданни от файл",
"CERTIFICATE": "SAML сертификат",
"DOWNLOADCERT": "Изтеглете SAML сертификат",
"CREATEMETADATA": "Създайте метаданни", "CREATEMETADATA": "Създайте метаданни",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2104,6 +2104,8 @@
"UPLOAD": "Nahrát XML soubor", "UPLOAD": "Nahrát XML soubor",
"METADATA": "Metadata", "METADATA": "Metadata",
"METADATAFROMFILE": "Metadata ze souboru", "METADATAFROMFILE": "Metadata ze souboru",
"CERTIFICATE": "certifikát SAML",
"DOWNLOADCERT": "Stáhněte si certifikát SAML",
"CREATEMETADATA": "Vytvořit metadata", "CREATEMETADATA": "Vytvořit metadata",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS koncová URL" "ACSURL": "ACS koncová URL"

View File

@ -2095,6 +2095,8 @@
"UPLOAD": "XML-Datei hochladen", "UPLOAD": "XML-Datei hochladen",
"METADATA": "Metadaten", "METADATA": "Metadaten",
"METADATAFROMFILE": "Metadata aus Datei", "METADATAFROMFILE": "Metadata aus Datei",
"CERTIFICATE": "SAML-Zertifikat",
"DOWNLOADCERT": "Laden Sie das SAML-Zertifikat herunter",
"CREATEMETADATA": "Create metadata", "CREATEMETADATA": "Create metadata",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2114,6 +2114,8 @@
"UPLOAD": "Upload XML file", "UPLOAD": "Upload XML file",
"METADATA": "Metadata", "METADATA": "Metadata",
"METADATAFROMFILE": "Metadata from file", "METADATAFROMFILE": "Metadata from file",
"CERTIFICATE": "SAML certificate",
"DOWNLOADCERT": "Download SAML certificate",
"CREATEMETADATA": "Create metadata", "CREATEMETADATA": "Create metadata",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2092,6 +2092,8 @@
"UPLOAD": "Subir fichero XML", "UPLOAD": "Subir fichero XML",
"METADATA": "Metadatos", "METADATA": "Metadatos",
"METADATAFROMFILE": "Metadatos desde un fichero", "METADATAFROMFILE": "Metadatos desde un fichero",
"CERTIFICATE": "Certificado SAML",
"DOWNLOADCERT": "Descargar certificado SAML",
"CREATEMETADATA": "Crear metadatos", "CREATEMETADATA": "Crear metadatos",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2096,6 +2096,8 @@
"UPLOAD": "Télécharger le fichier XML", "UPLOAD": "Télécharger le fichier XML",
"METADATA": "Métadonnées", "METADATA": "Métadonnées",
"METADATAFROMFILE": "Métadonnées du fichier", "METADATAFROMFILE": "Métadonnées du fichier",
"CERTIFICATE": "Certificat SAML",
"DOWNLOADCERT": "Télécharger le certificat SAML",
"CREATEMETADATA": "Créer des métadonnées", "CREATEMETADATA": "Créer des métadonnées",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2096,6 +2096,8 @@
"UPLOAD": "Carica il file XML", "UPLOAD": "Carica il file XML",
"METADATA": "Metadata", "METADATA": "Metadata",
"METADATAFROMFILE": "Metadati dal file", "METADATAFROMFILE": "Metadati dal file",
"CERTIFICATE": "Certificato SAML",
"DOWNLOADCERT": "Scarica il certificato SAML",
"CREATEMETADATA": "Crea metadati", "CREATEMETADATA": "Crea metadati",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2087,6 +2087,8 @@
"UPLOAD": "XMLファイルをアップロードする", "UPLOAD": "XMLファイルをアップロードする",
"METADATA": "メタデータ", "METADATA": "メタデータ",
"METADATAFROMFILE": "ファイルからのメタデータ", "METADATAFROMFILE": "ファイルからのメタデータ",
"CERTIFICATE": "SAML証明書",
"DOWNLOADCERT": "SAML証明書をダウンロードする",
"CREATEMETADATA": "メタデータの作成", "CREATEMETADATA": "メタデータの作成",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2093,6 +2093,8 @@
"UPLOAD": "Поставете XML датотека", "UPLOAD": "Поставете XML датотека",
"METADATA": "Метаподатоци", "METADATA": "Метаподатоци",
"METADATAFROMFILE": "Метаподатоци од датотека", "METADATAFROMFILE": "Метаподатоци од датотека",
"CERTIFICATE": "SAML сертификат",
"DOWNLOADCERT": "Преземете SAML сертификат",
"CREATEMETADATA": "Креирајте метаподатоци", "CREATEMETADATA": "Креирајте метаподатоци",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2096,6 +2096,8 @@
"UPLOAD": "Prześlij plik XML", "UPLOAD": "Prześlij plik XML",
"METADATA": "Metadane", "METADATA": "Metadane",
"METADATAFROMFILE": "Metadane z pliku", "METADATAFROMFILE": "Metadane z pliku",
"CERTIFICATE": "Certyfikat SAML-a",
"DOWNLOADCERT": "Pobierz certyfikat SAML",
"CREATEMETADATA": "Utwórz metadane", "CREATEMETADATA": "Utwórz metadane",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2091,6 +2091,8 @@
"UPLOAD": "Prześlij plik XML", "UPLOAD": "Prześlij plik XML",
"METADATA": "Metadados", "METADATA": "Metadados",
"METADATAFROMFILE": "Metadados do Arquivo", "METADATAFROMFILE": "Metadados do Arquivo",
"CERTIFICATE": "Certificado SAML",
"DOWNLOADCERT": "Baixar certificado SAML",
"CREATEMETADATA": "Criar metadados", "CREATEMETADATA": "Criar metadados",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"

View File

@ -2084,7 +2084,12 @@
"OR": "или", "OR": "или",
"XML": "Загрузить XML-метаданные", "XML": "Загрузить XML-метаданные",
"METADATA": "Метаданные", "METADATA": "Метаданные",
"METADATAFROMFILE": "Метаданные из файла" "METADATAFROMFILE": "Метаданные из файла",
"CERTIFICATE": "SAML-сертификат",
"DOWNLOADCERT": "Скачать сертификат SAML",
"CREATEMETADATA": "Создать метаданные",
"ENTITYID": "Идентификатор объекта",
"ACSURL": "URL-адрес конечной точки ACS"
}, },
"AUTHMETHODS": { "AUTHMETHODS": {
"CODE": { "CODE": {

View File

@ -2095,6 +2095,8 @@
"UPLOAD": "上传 XML 文件", "UPLOAD": "上传 XML 文件",
"METADATA": "元数据", "METADATA": "元数据",
"METADATAFROMFILE": "文件中的元数据", "METADATAFROMFILE": "文件中的元数据",
"CERTIFICATE": "SAML证书",
"DOWNLOADCERT": "下载 SAML 证书",
"CREATEMETADATA": "创建元数据", "CREATEMETADATA": "创建元数据",
"ENTITYID": "Entity ID", "ENTITYID": "Entity ID",
"ACSURL": "ACS endpoint URL" "ACSURL": "ACS endpoint URL"