mirror of
https://github.com/zitadel/zitadel.git
synced 2025-06-11 10:48:32 +00:00
feat(console): OAuth provider template (#5377)
implements oauth template for console Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
parent
1ec6c451ca
commit
0c704966a2
@ -46,6 +46,10 @@
|
||||
<mat-icon class="idp-icon" svgIcon="mdi_openid" alt="oidc" />
|
||||
Generic OIDC
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_OAUTH">
|
||||
<img class="idp-logo" src="../../../assets/images/idp/oauth.svg" alt="oauth" />
|
||||
Generic OAuth
|
||||
</div>
|
||||
<div class="idp-table-provider-type" *ngSwitchCase="ProviderType.PROVIDER_TYPE_JWT">
|
||||
<mat-icon class="idp-icon" svgIcon="mdi_jwt" alt="jwt" />
|
||||
Generic JWT
|
||||
|
@ -228,6 +228,8 @@ export class IdpTableComponent implements OnInit {
|
||||
switch (row.type) {
|
||||
case ProviderType.PROVIDER_TYPE_OIDC:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'oidc', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_OAUTH:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'oauth', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_JWT:
|
||||
return [row.owner === IDPOwnerType.IDP_OWNER_TYPE_SYSTEM ? '/instance' : '/org', 'provider', 'jwt', row.id];
|
||||
case ProviderType.PROVIDER_TYPE_GOOGLE:
|
||||
|
@ -68,6 +68,23 @@
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['/instance', 'provider', 'oauth', 'create']
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['/org', 'provider', 'oauth', 'create']
|
||||
: []
|
||||
"
|
||||
>
|
||||
<img class="idp-logo" src="../../../assets/images/idp/oauth.svg" alt="oauth" />
|
||||
|
||||
<div class="text-container">
|
||||
<span class="title">Generic OAuth</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="item card"
|
||||
[routerLink]="
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { ProviderOAuthComponent } from './provider-oauth.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ProviderOAuthComponent,
|
||||
data: { animation: 'DetailPage' },
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ProviderOAuthRoutingModule {}
|
@ -0,0 +1,111 @@
|
||||
<cnsl-create-layout
|
||||
title="{{ id ? ('IDP.DETAIL.TITLE' | translate) : ('IDP.CREATE.TITLE' | translate) }}"
|
||||
(closed)="close()"
|
||||
>
|
||||
<div class="oauth-create-content">
|
||||
<div class="title-row">
|
||||
<img class="idp-logo" src="../../../assets/images/idp/oauth.svg" alt="oauth" />
|
||||
|
||||
<h1>{{ 'IDP.CREATE.OAUTH.TITLE' | translate }}</h1>
|
||||
<mat-spinner diameter="25" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<p class="desc cnsl-secondary-text">{{ 'IDP.CREATE.OAUTH.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<form [formGroup]="form" (ngSubmit)="submitForm()">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.NAME' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="name" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.AUTHORIZATIONENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="authorizationEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.TOKENENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="tokenEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.USERENDPOINT' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="userEndpoint" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.IDATTRIBUTE' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="idAttribute" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="oauth-content">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTID' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientId" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<mat-checkbox *ngIf="provider" [(ngModel)]="updateClientSecret" [ngModelOptions]="{ standalone: true }">{{
|
||||
'IDP.UPDATECLIENTSECRET' | translate
|
||||
}}</mat-checkbox>
|
||||
<cnsl-form-field *ngIf="!provider || (provider && updateClientSecret)" class="formfield">
|
||||
<cnsl-label>{{ 'IDP.CLIENTSECRET' | translate }}</cnsl-label>
|
||||
<input cnslInput formControlName="clientSecret" />
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="optional-h-wrapper">
|
||||
<h2>{{ 'IDP.OPTIONAL' | translate }}</h2>
|
||||
<button (click)="showOptional = !showOptional" type="button" mat-icon-button>
|
||||
<mat-icon *ngIf="showOptional">keyboard_arrow_up</mat-icon
|
||||
><mat-icon *ngIf="!showOptional">keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showOptional">
|
||||
<div class="idp-scopes">
|
||||
<div class="flex-line">
|
||||
<cnsl-form-field class="formfield">
|
||||
<cnsl-label>{{ 'IDP.SCOPESLIST' | translate }}</cnsl-label>
|
||||
|
||||
<input
|
||||
cnslInput
|
||||
[matChipInputFor]="chipScopesList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
[matChipInputAddOnBlur]="true"
|
||||
(matChipInputTokenEnd)="addScope($event)"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
<button class="scope-add-button" (click)="addScope($any($event))" mat-icon-button>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<cnsl-form-field class="formfield">
|
||||
<mat-chip-list #chipScopesList aria-label="scope selection">
|
||||
<mat-chip
|
||||
class="chip"
|
||||
*ngFor="let scope of scopesList?.value"
|
||||
selectable="false"
|
||||
removable
|
||||
(removed)="removeScope(scope)"
|
||||
>
|
||||
{{ scope }} <mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
|
||||
<cnsl-provider-options
|
||||
[initialOptions]="provider?.config?.options"
|
||||
(optionsChanged)="options = $event"
|
||||
></cnsl-provider-options>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oauth-create-actions">
|
||||
<button color="primary" mat-raised-button class="continue-button" [disabled]="form.invalid" type="submit">
|
||||
<span *ngIf="id">{{ 'ACTIONS.SAVE' | translate }}</span>
|
||||
<span *ngIf="!id">{{ 'ACTIONS.CREATE' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</cnsl-create-layout>
|
@ -0,0 +1,84 @@
|
||||
.desc {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.oauth-create-content {
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.idp-logo {
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.formfield {
|
||||
display: block;
|
||||
max-width: 400px;
|
||||
|
||||
.mat-chip-input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chip {
|
||||
border-radius: 0.5rem;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
.oauth-content {
|
||||
.desc {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.idp-scopes {
|
||||
padding-bottom: 0.5rem;
|
||||
|
||||
.flex-line {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
max-width: 400px;
|
||||
|
||||
.formfield {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.scope-add-button {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.oauth-create-actions {
|
||||
display: flex;
|
||||
margin-top: 1rem;
|
||||
|
||||
button[mat-raised-button] {
|
||||
border-radius: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
padding: 0.5rem 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.optional-h-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProviderOAuthComponent } from './provider-oauth.component';
|
||||
|
||||
describe('ProviderOAuthComponent', () => {
|
||||
let component: ProviderOAuthComponent;
|
||||
let fixture: ComponentFixture<ProviderOAuthComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderOAuthComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProviderOAuthComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,298 @@
|
||||
import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes';
|
||||
import { Location } from '@angular/common';
|
||||
import { Component, Injector, Type } from '@angular/core';
|
||||
import { AbstractControl, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MatLegacyChipInputEvent as MatChipInputEvent } from '@angular/material/legacy-chips';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { take } from 'rxjs';
|
||||
import {
|
||||
AddGenericOAuthProviderRequest as AdminAddGenericOAuthProviderRequest,
|
||||
GetProviderByIDRequest as AdminGetProviderByIDRequest,
|
||||
UpdateGenericOAuthProviderRequest as AdminUpdateGenericOAuthProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import { Options, Provider } from 'src/app/proto/generated/zitadel/idp_pb';
|
||||
import {
|
||||
AddGenericOAuthProviderRequest as MgmtAddGenericOAuthProviderRequest,
|
||||
GetProviderByIDRequest as MgmtGetProviderByIDRequest,
|
||||
UpdateGenericOAuthProviderRequest as MgmtUpdateGenericOAuthProviderRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { PolicyComponentServiceType } from '../../policies/policy-component-types.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-provider-oauth',
|
||||
templateUrl: './provider-oauth.component.html',
|
||||
styleUrls: ['./provider-oauth.component.scss'],
|
||||
})
|
||||
export class ProviderOAuthComponent {
|
||||
public showOptional: boolean = false;
|
||||
public options: Options = new Options();
|
||||
|
||||
public id: string | null = '';
|
||||
public updateClientSecret: boolean = false;
|
||||
public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT;
|
||||
private service!: ManagementService | AdminService;
|
||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||
public form!: UntypedFormGroup;
|
||||
|
||||
public loading: boolean = false;
|
||||
|
||||
public provider?: Provider.AsObject;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private _location: Location,
|
||||
breadcrumbService: BreadcrumbService,
|
||||
) {
|
||||
this.form = new UntypedFormGroup({
|
||||
name: new UntypedFormControl('', [Validators.required]),
|
||||
clientId: new UntypedFormControl('', [Validators.required]),
|
||||
clientSecret: new UntypedFormControl('', [Validators.required]),
|
||||
authorizationEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
tokenEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
userEndpoint: new UntypedFormControl('', [Validators.required]),
|
||||
idAttribute: new UntypedFormControl('', [Validators.required]),
|
||||
scopesList: new UntypedFormControl(['openid', 'profile', 'email'], []),
|
||||
});
|
||||
|
||||
this.route.data.pipe(take(1)).subscribe((data) => {
|
||||
this.serviceType = data.serviceType;
|
||||
|
||||
switch (this.serviceType) {
|
||||
case PolicyComponentServiceType.MGMT:
|
||||
this.service = this.injector.get(ManagementService as Type<ManagementService>);
|
||||
|
||||
const bread: Breadcrumb = {
|
||||
type: BreadcrumbType.ORG,
|
||||
routerLink: ['/org'],
|
||||
};
|
||||
|
||||
breadcrumbService.setBreadcrumb([bread]);
|
||||
break;
|
||||
case PolicyComponentServiceType.ADMIN:
|
||||
this.service = this.injector.get(AdminService as Type<AdminService>);
|
||||
|
||||
const iamBread = new Breadcrumb({
|
||||
type: BreadcrumbType.ORG,
|
||||
name: 'Instance',
|
||||
routerLink: ['/instance'],
|
||||
});
|
||||
breadcrumbService.setBreadcrumb([iamBread]);
|
||||
break;
|
||||
}
|
||||
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
if (this.id) {
|
||||
this.clientSecret?.setValidators([]);
|
||||
this.getData(this.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private getData(id: string): void {
|
||||
this.loading = true;
|
||||
const req =
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? new AdminGetProviderByIDRequest()
|
||||
: new MgmtGetProviderByIDRequest();
|
||||
req.setId(id);
|
||||
this.service
|
||||
.getProviderByID(req)
|
||||
.then((resp) => {
|
||||
this.provider = resp.idp;
|
||||
this.loading = false;
|
||||
if (this.provider?.config?.oauth) {
|
||||
this.form.patchValue(this.provider.config.oauth);
|
||||
this.name?.setValue(this.provider.name);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
public submitForm(): void {
|
||||
this.provider ? this.updateGenericOAuthProvider() : this.addGenericOAuthProvider();
|
||||
}
|
||||
|
||||
public addGenericOAuthProvider(): void {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtAddGenericOAuthProviderRequest();
|
||||
|
||||
req.setName(this.name?.value);
|
||||
req.setAuthorizationEndpoint(this.authorizationEndpoint?.value);
|
||||
req.setIdAttribute(this.idAttribute?.value);
|
||||
req.setTokenEndpoint(this.tokenEndpoint?.value);
|
||||
req.setUserEndpoint(this.userEndpoint?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.addGenericOAuthProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminAddGenericOAuthProviderRequest();
|
||||
req.setName(this.name?.value);
|
||||
req.setAuthorizationEndpoint(this.authorizationEndpoint?.value);
|
||||
req.setIdAttribute(this.idAttribute?.value);
|
||||
req.setTokenEndpoint(this.tokenEndpoint?.value);
|
||||
req.setUserEndpoint(this.userEndpoint?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.addGenericOAuthProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public updateGenericOAuthProvider(): void {
|
||||
if (this.provider) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
const req = new MgmtUpdateGenericOAuthProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setAuthorizationEndpoint(this.authorizationEndpoint?.value);
|
||||
req.setIdAttribute(this.idAttribute?.value);
|
||||
req.setTokenEndpoint(this.tokenEndpoint?.value);
|
||||
req.setUserEndpoint(this.userEndpoint?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as ManagementService)
|
||||
.updateGenericOAuthProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/org-settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (PolicyComponentServiceType.ADMIN) {
|
||||
const req = new AdminUpdateGenericOAuthProviderRequest();
|
||||
req.setId(this.provider.id);
|
||||
req.setName(this.name?.value);
|
||||
req.setAuthorizationEndpoint(this.authorizationEndpoint?.value);
|
||||
req.setIdAttribute(this.idAttribute?.value);
|
||||
req.setTokenEndpoint(this.tokenEndpoint?.value);
|
||||
req.setUserEndpoint(this.userEndpoint?.value);
|
||||
req.setClientId(this.clientId?.value);
|
||||
req.setClientSecret(this.clientSecret?.value);
|
||||
req.setScopesList(this.scopesList?.value);
|
||||
|
||||
this.loading = true;
|
||||
(this.service as AdminService)
|
||||
.updateGenericOAuthProvider(req)
|
||||
.then((idp) => {
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
this.router.navigate(['/settings'], { queryParams: { id: 'idp' } });
|
||||
}, 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._location.back();
|
||||
}
|
||||
|
||||
public addScope(event: MatChipInputEvent): void {
|
||||
const input = event.chipInput?.inputElement;
|
||||
const value = event.value.trim();
|
||||
|
||||
if (value !== '') {
|
||||
if (this.scopesList?.value) {
|
||||
this.scopesList.value.push(value);
|
||||
if (input) {
|
||||
input.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeScope(uri: string): void {
|
||||
if (this.scopesList?.value) {
|
||||
const index = this.scopesList.value.indexOf(uri);
|
||||
|
||||
if (index !== undefined && index >= 0) {
|
||||
this.scopesList.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): AbstractControl | null {
|
||||
return this.form.get('name');
|
||||
}
|
||||
|
||||
public get authorizationEndpoint(): AbstractControl | null {
|
||||
return this.form.get('authorizationEndpoint');
|
||||
}
|
||||
|
||||
public get tokenEndpoint(): AbstractControl | null {
|
||||
return this.form.get('tokenEndpoint');
|
||||
}
|
||||
|
||||
public get userEndpoint(): AbstractControl | null {
|
||||
return this.form.get('userEndpoint');
|
||||
}
|
||||
|
||||
public get idAttribute(): AbstractControl | null {
|
||||
return this.form.get('idAttribute');
|
||||
}
|
||||
|
||||
public get clientId(): AbstractControl | null {
|
||||
return this.form.get('clientId');
|
||||
}
|
||||
|
||||
public get clientSecret(): AbstractControl | null {
|
||||
return this.form.get('clientSecret');
|
||||
}
|
||||
|
||||
public get issuer(): AbstractControl | null {
|
||||
return this.form.get('issuer');
|
||||
}
|
||||
|
||||
public get scopesList(): AbstractControl | null {
|
||||
return this.form.get('scopesList');
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||
import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox';
|
||||
import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips';
|
||||
import { MatLegacyProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InputModule } from 'src/app/modules/input/input.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { CreateLayoutModule } from '../../create-layout/create-layout.module';
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { ProviderOptionsModule } from '../../provider-options/provider-options.module';
|
||||
import { ProviderOAuthRoutingModule } from './provider-oauth-routing.module';
|
||||
import { ProviderOAuthComponent } from './provider-oauth.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProviderOAuthComponent],
|
||||
imports: [
|
||||
ProviderOAuthRoutingModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CreateLayoutModule,
|
||||
InfoSectionModule,
|
||||
InputModule,
|
||||
MatButtonModule,
|
||||
MatSelectModule,
|
||||
MatIconModule,
|
||||
MatChipsModule,
|
||||
CardModule,
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
TranslateModule,
|
||||
ProviderOptionsModule,
|
||||
MatLegacyProgressSpinnerModule,
|
||||
],
|
||||
})
|
||||
export default class ProviderOAuthModule {}
|
@ -44,6 +44,19 @@ const routes: Routes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'oauth',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oauth/provider-oauth.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oauth/provider-oauth.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'jwt',
|
||||
children: [
|
||||
|
@ -19,6 +19,19 @@ const routes: Routes = [
|
||||
serviceType: PolicyComponentServiceType.MGMT,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'oauth',
|
||||
children: [
|
||||
{
|
||||
path: 'create',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oauth/provider-oauth.module'),
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('src/app/modules/providers/provider-oauth/provider-oauth.module'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'oidc',
|
||||
children: [
|
||||
|
@ -8,6 +8,8 @@ import {
|
||||
ActivateSMSProviderResponse,
|
||||
AddCustomDomainPolicyRequest,
|
||||
AddCustomOrgIAMPolicyResponse,
|
||||
AddGenericOAuthProviderRequest,
|
||||
AddGenericOAuthProviderResponse,
|
||||
AddGenericOIDCProviderRequest,
|
||||
AddGenericOIDCProviderResponse,
|
||||
AddGoogleProviderRequest,
|
||||
@ -194,6 +196,8 @@ import {
|
||||
UpdateCustomDomainPolicyResponse,
|
||||
UpdateDomainPolicyRequest,
|
||||
UpdateDomainPolicyResponse,
|
||||
UpdateGenericOAuthProviderRequest,
|
||||
UpdateGenericOAuthProviderResponse,
|
||||
UpdateGenericOIDCProviderRequest,
|
||||
UpdateGenericOIDCProviderResponse,
|
||||
UpdateGoogleProviderRequest,
|
||||
@ -912,6 +916,16 @@ export class AdminService {
|
||||
return this.grpcService.admin.updateGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGenericOAuthProvider(req: AddGenericOAuthProviderRequest): Promise<AddGenericOAuthProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addGenericOAuthProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateGenericOAuthProvider(
|
||||
req: UpdateGenericOAuthProviderRequest,
|
||||
): Promise<UpdateGenericOAuthProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.updateGenericOAuthProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addJWTProvider(req: AddJWTProviderRequest): Promise<AddJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.admin.addJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
@ -29,6 +29,8 @@ import {
|
||||
AddCustomPasswordComplexityPolicyResponse,
|
||||
AddCustomPrivacyPolicyRequest,
|
||||
AddCustomPrivacyPolicyResponse,
|
||||
AddGenericOAuthProviderRequest,
|
||||
AddGenericOAuthProviderResponse,
|
||||
AddGenericOIDCProviderRequest,
|
||||
AddGenericOIDCProviderResponse,
|
||||
AddGoogleProviderRequest,
|
||||
@ -427,6 +429,8 @@ import {
|
||||
UpdateCustomPasswordComplexityPolicyResponse,
|
||||
UpdateCustomPrivacyPolicyRequest,
|
||||
UpdateCustomPrivacyPolicyResponse,
|
||||
UpdateGenericOAuthProviderRequest,
|
||||
UpdateGenericOAuthProviderResponse,
|
||||
UpdateGenericOIDCProviderRequest,
|
||||
UpdateGenericOIDCProviderResponse,
|
||||
UpdateGoogleProviderRequest,
|
||||
@ -871,6 +875,16 @@ export class ManagementService {
|
||||
return this.grpcService.mgmt.updateGenericOIDCProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addGenericOAuthProvider(req: AddGenericOAuthProviderRequest): Promise<AddGenericOAuthProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addGenericOAuthProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public updateGenericOAuthProvider(
|
||||
req: UpdateGenericOAuthProviderRequest,
|
||||
): Promise<UpdateGenericOAuthProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.updateGenericOAuthProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public addJWTProvider(req: AddJWTProviderRequest): Promise<AddJWTProviderResponse.AsObject> {
|
||||
return this.grpcService.mgmt.addJWTProvider(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
@ -1674,6 +1674,10 @@
|
||||
"SETAVAILABLE": "verfügbar setzen",
|
||||
"SETUNAVAILABLE": "auf nicht verfügbar setzen",
|
||||
"NAME": "Name",
|
||||
"AUTHORIZATIONENDPOINT": "Authorization Endpunkt",
|
||||
"TOKENENDPOINT": "Token Endpunkt",
|
||||
"USERENDPOINT": "User Endpunkt",
|
||||
"IDATTRIBUTE": "ID Attribut",
|
||||
"CONFIG": "Konfiguration",
|
||||
"STATE": "Status",
|
||||
"ISSUER": "Issuer",
|
||||
@ -1694,10 +1698,13 @@
|
||||
"DELETE_SELECTION_DESCRIPTION": "Sie sind im Begriff mehrere Identity Provider zu löschen. Die dadurch hervorgerufenen Änderungen sind unwiderruflich. Wollen Sie dies wirklich tun?",
|
||||
"EMPTY": "Kein IDP vorhanden",
|
||||
"OIDC": {
|
||||
"GENERAL": "Generelle Information",
|
||||
"TITLE": "OIDC Konfiguration",
|
||||
"DESCRIPTION": "Geben Sie die Daten OIDC Identity Providers ein."
|
||||
},
|
||||
"OAUTH": {
|
||||
"TITLE": "OAuth Konfiguration",
|
||||
"DESCRIPTION": "Geben Sie die Daten OAuth Identity Providers ein."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Konfiguration",
|
||||
"DESCRIPTION": "Geben Sie die Daten JWT Identity Providers ein. ",
|
||||
|
@ -1623,6 +1623,10 @@
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Enter the required data for your OIDC provider."
|
||||
},
|
||||
"OAUTH": {
|
||||
"TITLE": "OAuth Provider",
|
||||
"DESCRIPTION": "Enter the required data for your OAuth provider."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Enter the required data for your JWT provider."
|
||||
@ -1665,6 +1669,10 @@
|
||||
"OWNER": "Owner",
|
||||
"ID": "ID",
|
||||
"NAME": "Name",
|
||||
"AUTHORIZATIONENDPOINT": "Authorization Endpoint",
|
||||
"TOKENENDPOINT": "Token Endpoint",
|
||||
"USERENDPOINT": "User Endpoint",
|
||||
"IDATTRIBUTE": "ID Attribute",
|
||||
"AVAILABILITY": "Availability",
|
||||
"AVAILABLE": "available",
|
||||
"AVAILABLEBUTINACTIVE": "available but inactive",
|
||||
|
@ -1622,6 +1622,10 @@
|
||||
"TITLE": "Fournisseur OIDC",
|
||||
"DESCRIPTION": "Entrez les données requises pour votre fournisseur OIDC."
|
||||
},
|
||||
"OAuth": {
|
||||
"TITLE": "Fournisseur OAuth",
|
||||
"DESCRIPTION": "Entrez les données requises pour votre fournisseur OAuth."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "Fournisseur JWT",
|
||||
"DESCRIPTION": "Entrez les données requises pour votre fournisseur JWT."
|
||||
@ -1669,6 +1673,10 @@
|
||||
"OWNER": "Propriétaire",
|
||||
"ID": "ID",
|
||||
"NAME": "Nom",
|
||||
"AUTHORIZATIONENDPOINT": "Authorization Endpoint",
|
||||
"TOKENENDPOINT": "Token Endpoint",
|
||||
"USERENDPOINT": "User Endpoint",
|
||||
"IDATTRIBUTE": "Attribut d'identification",
|
||||
"AVAILABILITY": "Disponibilité",
|
||||
"AVAILABLE": "disponible",
|
||||
"AVAILABLEBUTINACTIVE": "disponible mais inactif",
|
||||
|
@ -1623,6 +1623,10 @@
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo provider OIDC."
|
||||
},
|
||||
"OAuth": {
|
||||
"TITLE": "OAuth Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo provider OAuth."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Inserisci i dati necessari per il tuo provider JWT."
|
||||
@ -1670,6 +1674,10 @@
|
||||
"OWNER": "Owner",
|
||||
"ID": "ID",
|
||||
"NAME": "Nome",
|
||||
"AUTHORIZATIONENDPOINT": "Authorization Endpoint",
|
||||
"TOKENENDPOINT": "Token Endpoint",
|
||||
"USERENDPOINT": "User Endpoint",
|
||||
"IDATTRIBUTE": "Attributo ID",
|
||||
"AVAILABILITY": "Disponibilità",
|
||||
"AVAILABLE": "disponibile",
|
||||
"AVAILABLEBUTINACTIVE": "disponible ma inattivo",
|
||||
|
@ -1622,6 +1622,10 @@
|
||||
"TITLE": "OIDC Provider",
|
||||
"DESCRIPTION": "Wprowadź wymagane dane dla swojego dostawcy OIDC."
|
||||
},
|
||||
"OAUTH": {
|
||||
"TITLE": "OAuth Provider",
|
||||
"DESCRIPTION": "Wprowadź wymagane dane dla swojego dostawcy OAuth."
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT Provider",
|
||||
"DESCRIPTION": "Wprowadź wymagane dane dla swojego dostawcy JWT."
|
||||
@ -1669,6 +1673,10 @@
|
||||
"OWNER": "Właściciel",
|
||||
"ID": "ID",
|
||||
"NAME": "Nazwa",
|
||||
"AUTHORIZATIONENDPOINT": "Authorization Endpoint",
|
||||
"TOKENENDPOINT": "Token Endpoint",
|
||||
"USERENDPOINT": "User Endpoint",
|
||||
"IDATTRIBUTE": "Atrybut identyfikatora",
|
||||
"AVAILABILITY": "Dostępność",
|
||||
"AVAILABLE": "dostępny",
|
||||
"AVAILABLEBUTINACTIVE": "dostępny ale nieaktywny",
|
||||
|
@ -1621,6 +1621,10 @@
|
||||
"TITLE": "OIDC供应商",
|
||||
"DESCRIPTION": "输入你的OIDC供应商的必要数据。"
|
||||
},
|
||||
"OAUTH": {
|
||||
"TITLE": "OAuth供应商",
|
||||
"DESCRIPTION": "输入你的OAuth供应商的必要数据。"
|
||||
},
|
||||
"JWT": {
|
||||
"TITLE": "JWT供应商",
|
||||
"DESCRIPTION": "输入你的JWT供应商所需的数据。"
|
||||
@ -1668,6 +1672,10 @@
|
||||
"OWNER": "所有者",
|
||||
"ID": "ID",
|
||||
"NAME": "名称",
|
||||
"AUTHORIZATIONENDPOINT": "授权端点",
|
||||
"TOKENENDPOINT": "令牌端点",
|
||||
"USERENDPOINT": "用户端点",
|
||||
"IDATTRIBUTE": "标识属性",
|
||||
"AVAILABILITY": "可用性",
|
||||
"AVAILABLE": "可用的",
|
||||
"AVAILABLEBUTINACTIVE": "可用但已停用",
|
||||
|
61
console/src/assets/images/idp/oauth.svg
Normal file
61
console/src/assets/images/idp/oauth.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14576) -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.0" x="0px" y="0px" width="598.48541" height="599.83948" viewBox="0 0 598.486 671.089" enable-background="new 0 0 598.486 671.089">
|
||||
<g transform="translate(0,35.625)">
|
||||
<path fill="#fff" d="M 277.7249,0.87048682 C 410.2899,-8.3215132 498.1879,56.550487 548.4459,135.58949 C 573.6459,175.21949 598.3709,235.40949 598.4849,297.25249 C 598.6069,364.44649 576.8389,422.63549 548.4459,465.33049 C 519.2639,509.21349 481.5199,545.45849 434.2559,569.25749 C 355.2499,609.04049 244.8359,610.12849 172.5149,571.82349 C 91.972897,529.16549 30.046897,468.27849 7.0028967,362.68749 C -2.2191033,320.43149 -3.2791033,265.83249 9.5688967,218.98749 C 12.583897,207.99849 18.062897,196.43349 22.399897,185.62849 C 43.241897,133.70449 78.716897,88.552487 122.4769,57.323487 C 140.0609,44.775487 161.3929,32.295487 180.2139,23.964487 C 203.6319,13.599487 243.0599,3.2734868 277.7249,0.87048682 z" />
|
||||
<path fill="#000" d="M 529.1839,304.72449 C 529.1839,430.01249 427.6179,531.57149 302.3319,531.57149 C 177.0459,531.57149 75.481897,430.01249 75.481897,304.72449 C 75.481897,179.43949 177.0459,77.872487 302.3319,77.872487 C 427.6169,77.872487 529.1839,179.43949 529.1839,304.72449 z" />
|
||||
<path fill="#000" d="M 277.7249,0.87048682 C 410.2899,-8.3215132 498.1879,56.550487 548.4459,135.58949 C 573.6459,175.21949 598.3709,235.40949 598.4849,297.25249 C 598.6069,364.44649 576.8389,422.63549 548.4459,465.33049 C 519.2639,509.21349 481.5199,545.45849 434.2559,569.25749 C 355.2499,609.04049 244.8359,610.12849 172.5149,571.82349 C 91.972897,529.16549 30.046897,468.27849 7.0028967,362.68749 C -2.2191033,320.43149 -3.2791033,265.83249 9.5688967,218.98749 C 12.583897,207.99849 18.062897,196.43349 22.399897,185.62849 C 43.241897,133.70449 78.716897,88.552487 122.4769,57.323487 C 140.0609,44.775487 161.3929,32.295487 180.2139,23.964487 C 203.6319,13.599487 243.0599,3.2734868 277.7249,0.87048682 z M 232.8179,22.682487 C 183.5789,35.448487 147.4759,58.319487 116.0619,82.985487 C 70.762897,118.55349 41.884897,168.18849 24.965897,227.96849 C 6.1428967,294.47649 18.233897,374.95849 44.211897,425.55649 C 71.150897,478.02849 107.3219,518.75949 158.4019,547.44549 C 208.0969,575.35349 277.9929,593.27349 350.8589,579.52149 C 415.5989,567.30349 464.7679,539.10049 504.8239,497.40649 C 558.4159,441.62149 601.4889,338.87249 572.8259,230.53449 C 565.1639,201.57949 555.1469,171.40149 539.4659,145.85349 C 530.9939,132.05149 518.5619,118.47349 506.1069,104.79649 C 459.1009,53.175487 383.1279,8.6924868 285.4229,14.983487 C 266.8289,16.180487 250.4879,18.100487 232.8179,22.682487 z" />
|
||||
<g style="fill:none;stroke:#fff;stroke-width:2" id="hashpattern">
|
||||
<g>
|
||||
<line y2="314.658" x2="578.188" y1="576.79" x1="316.05"/>
|
||||
<line y2="292.754" x2="556.415" y1="556.03" x1="293.134"/>
|
||||
<line y2="270.851" x2="534.643" y1="535.273" x1="270.217"/>
|
||||
<line y2="248.948" x2="512.87" y1="514.513" x1="247.3"/>
|
||||
<line y2="227.044" x2="491.098" y1="493.754" x1="224.384"/>
|
||||
<line y2="205.141" x2="469.324" y1="473" x1="201.467"/>
|
||||
<line y2="183.238" x2="447.552" y1="452.236" x1="178.55"/>
|
||||
<line y2="161.334" x2="425.778" y1="431.477" x1="155.633"/>
|
||||
<line y2="139.431" x2="404" y1="410.718" x1="132.716"/>
|
||||
<line y2="117.528" x2="382.233" y1="389.958" x1="109.8"/>
|
||||
<line y2="95.625" x2="360.46" y1="369.2" x1="86.883"/>
|
||||
<line y2="73.721" x2="338.688" y1="348.441" x1="63.966"/>
|
||||
<line y2="51.818" x2="316.915" y1="327.681" x1="41.049"/>
|
||||
<line y2="29.915" x2="295.142" y1="306.922" x1="18.132"/>
|
||||
</g>
|
||||
<g>
|
||||
<line y2="576.96" x2="285.419" y1="309.572" x1="18.043" />
|
||||
<line y2="555.488" x2="307.622" y1="287.579" x1="39.726" />
|
||||
<line y2="534.014" x2="329.825" y1="265.586" x1="61.409" />
|
||||
<line y2="512.542" x2="352.029" y1="243.593" x1="83.092" />
|
||||
<line y2="491.068" x2="374.231" y1="221.6" x1="104.774"/>
|
||||
<line y2="469.595" x2="396.436" y1="199.607" x1="126.457"/>
|
||||
<line y2="448.122" x2="418.639" y1="177.614" x1="148.14" />
|
||||
<line y2="426.648" x2="440.842" y1="155.621" x1="169.822"/>
|
||||
<line y2="405.175" x2="463.046" y1="133.628" x1="191.505"/>
|
||||
<line y2="383.7" x2="485.248" y1="111.635" x1="213.188"/>
|
||||
<line y2="362.229" x2="507.452" y1="89.642" x1="234.871"/>
|
||||
<line y2="340.755" x2="529.655" y1="67.649" x1="256.553"/>
|
||||
<line y2="319.283" x2="551.858" y1="45.657" x1="278.236"/>
|
||||
<line y2="297.809" x2="574.062" y1="23.664" x1="299.92" />
|
||||
</g>
|
||||
</g>
|
||||
<path d="M 490.7099,106.07949 C 467.1169,82.486487 438.1109,61.226487 403.4629,48.342487 C 367.5489,34.987487 326.9229,23.730487 279.0079,27.813487 C 202.6819,34.319487 149.0919,68.564487 108.3629,108.64549 C 79.834897,136.71849 58.375897,171.11949 44.210897,211.28849 C 23.412897,270.26949 24.674897,339.88649 48.059897,399.89549 C 68.006897,451.08249 100.6549,492.36849 146.8539,524.35049 C 190.2849,554.41749 252.6189,577.73649 322.6299,571.82349 C 407.9019,564.62149 470.2939,520.87349 511.2369,470.46349 C 521.7129,457.56749 532.1289,442.99049 538.1799,425.55749 C 544.1089,412.99649 547.0109,404.45749 549.7279,399.89649 C 561.0999,374.41449 567.1249,347.52849 568.9729,317.78249 C 574.6579,226.29049 539.4559,154.82649 490.7099,106.07949 z M 465.5789,384.82749 C 465.4159,385.17549 465.2699,385.49949 465.0999,385.85849 C 460.8699,397.96349 453.5829,408.08549 446.2589,417.04149 C 417.6249,452.04549 373.9959,482.42349 314.3639,487.42549 C 265.4029,491.52949 221.8119,475.33849 191.4409,454.46049 C 165.0489,436.31749 144.9869,413.85949 130.9189,386.86949 C 130.0609,385.24549 121.8909,366.42249 121.8669,365.59449 C 110.7219,331.02549 109.7549,275.43949 121.1939,242.08249 C 128.8279,219.81949 141.5509,195.73149 158.4019,176.64749 C 181.6679,150.29649 204.9509,133.41149 241.7999,121.47649 C 258.6249,116.02649 273.6869,110.47949 294.4039,109.92949 C 344.9239,108.58449 396.3689,131.26749 423.9909,156.11849 C 449.3749,178.95549 478.3049,223.44049 485.5779,265.17649 C 493.0629,308.13349 485.0749,350.07449 465.5789,384.82749 z" />
|
||||
<path stroke="#000" stroke-width="6" fill="#fff" d="M 377.768,426.033 C 365.328,426.033 354.411,418.155 350.601,406.429 L 336.745,364.211 L 267.43,364.211 L 254.556,406.044 C 250.67,417.998 239.67,426 227.166,426 C 224.164,426 221.182,425.525 218.303,424.591 C 203.357,420.104 194.872,404.017 199.451,388.751 L 257.957,203.428 C 261.756,191.639 272.94,183.416 285.157,183.416 L 316.267,183.416 C 328.553,183.416 339.736,191.499 343.461,203.073 L 404.99,388.327 C 409.91,403.473 401.763,419.732 386.839,424.59 C 383.888,425.548 380.837,426.033 377.768,426.033 L 377.768,426.033 z" />
|
||||
<g id="OAUTH" fill="#fff">
|
||||
<g>
|
||||
<path d="M 148.001,124.354 L 147.928,124.255 C 140.632,114.256 142.773,100.268 153.518,92.426 C 164.263,84.585 178.066,86.786 185.362,96.784 L 185.435,96.883 C 192.731,106.882 190.59,120.871 179.845,128.712 C 169.1,136.553 155.297,134.353 148.001,124.354 z M 175.658,104.171 L 175.585,104.072 C 171.919,99.048 165.093,97.32 159.771,101.204 C 154.498,105.052 154.088,111.907 157.754,116.932 L 157.827,117.031 C 161.494,122.055 168.319,123.783 173.592,119.935 C 178.915,116.051 179.325,109.196 175.658,104.171 z" />
|
||||
<path d="M 218.344,58.817 L 229.309,55.299 L 260.048,91.033 L 247.851,94.946 L 242.509,88.576 L 226.676,93.656 L 226.096,101.927 L 214.134,105.765 L 218.344,58.817 z M 236.384,80.775 L 228.066,70.573 L 227.177,83.729 L 236.384,80.775 z" />
|
||||
<path d="M 279.795,69.567 L 279.891,45.364 L 292.023,45.412 L 291.928,69.369 C 291.903,75.589 295.032,78.557 299.836,78.577 C 304.64,78.596 307.792,75.776 307.815,69.741 L 307.912,45.477 L 320.044,45.525 L 319.949,69.42 C 319.894,83.338 311.926,89.404 299.67,89.355 C 287.415,89.305 279.742,83.054 279.795,69.567 z" />
|
||||
<path d="M 363.859,65.338 L 351.491,61.563 L 354.547,51.55 L 390.71,62.587 L 387.654,72.6 L 375.286,68.826 L 365.759,100.042 L 354.333,96.555 L 363.859,65.338 z" />
|
||||
<path d="M 423.012,76.559 L 432.958,83.178 L 424.02,96.61 L 436.786,105.106 L 445.725,91.673 L 455.671,98.292 L 431.788,134.181 L 421.841,127.562 L 430.917,113.924 L 418.15,105.428 L 409.075,119.066 L 399.129,112.447 L 423.012,76.559 z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M 458.146,468.883 L 458.222,468.98 C 465.896,478.693 464.29,492.755 453.852,501.001 C 443.414,509.247 429.536,507.575 421.862,497.862 L 421.786,497.765 C 414.112,488.051 415.719,473.99 426.156,465.744 C 436.594,457.499 450.472,459.17 458.146,468.883 z M 431.277,490.11 L 431.353,490.207 C 435.209,495.088 442.096,496.554 447.267,492.469 C 452.389,488.422 452.538,481.556 448.681,476.675 L 448.605,476.578 C 444.75,471.697 437.862,470.231 432.74,474.278 C 427.569,478.363 427.421,485.229 431.277,490.11 z"/>
|
||||
<path d="M 390.707,537.182 L 379.907,541.179 L 347.625,506.833 L 359.638,502.386 L 365.256,508.516 L 380.85,502.744 L 381.065,494.456 L 392.847,490.095 L 390.707,537.182 z M 371.718,516.04 L 380.477,525.865 L 380.786,512.683 L 371.718,516.04 z"/>
|
||||
<path d="M 328.888,528.985 L 329.955,553.164 L 317.835,553.699 L 316.778,529.766 C 316.504,523.552 313.236,520.738 308.437,520.95 C 303.638,521.162 300.625,524.131 300.891,530.16 L 301.961,554.4 L 289.841,554.935 L 288.787,531.064 C 288.173,517.16 295.841,510.718 308.084,510.178 C 320.328,509.637 328.293,515.511 328.888,528.985 z"/>
|
||||
<path d="M 244.671,536.891 L 257.158,540.262 L 254.429,550.37 L 217.918,540.515 L 220.647,530.406 L 233.134,533.777 L 241.641,502.261 L 253.177,505.375 L 244.671,536.891 z"/>
|
||||
<path d="M 185.65,528.108 L 175.401,521.966 L 183.696,508.125 L 170.543,500.241 L 162.248,514.082 L 152,507.94 L 174.164,470.961 L 184.412,477.104 L 175.99,491.156 L 189.144,499.04 L 197.566,484.988 L 207.814,491.131 L 185.65,528.108 z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 9.6 KiB |
Loading…
x
Reference in New Issue
Block a user