mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 07:37:24 +00:00
Merge branch 'main' into eventstore-created-at
This commit is contained in:
commit
defa429eb7
@ -96,4 +96,16 @@ protoc \
|
|||||||
--validate_out=lang=go:${GOPATH}/src \
|
--validate_out=lang=go:${GOPATH}/src \
|
||||||
${PROTO_PATH}/session/v2alpha/session_service.proto
|
${PROTO_PATH}/session/v2alpha/session_service.proto
|
||||||
|
|
||||||
|
protoc \
|
||||||
|
-I=/proto/include \
|
||||||
|
--grpc-gateway_out ${GOPATH}/src \
|
||||||
|
--grpc-gateway_opt logtostderr=true \
|
||||||
|
--grpc-gateway_opt allow_delete_body=true \
|
||||||
|
--openapiv2_out ${OPENAPI_PATH} \
|
||||||
|
--openapiv2_opt logtostderr=true \
|
||||||
|
--openapiv2_opt allow_delete_body=true \
|
||||||
|
--zitadel_out=${GOPATH}/src \
|
||||||
|
--validate_out=lang=go:${GOPATH}/src \
|
||||||
|
${PROTO_PATH}/settings/v2alpha/settings_service.proto
|
||||||
|
|
||||||
echo "done generating grpc"
|
echo "done generating grpc"
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@ -22,7 +21,6 @@ import (
|
|||||||
"github.com/zitadel/saml/pkg/provider"
|
"github.com/zitadel/saml/pkg/provider"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/cmd/key"
|
"github.com/zitadel/zitadel/cmd/key"
|
||||||
cmd_tls "github.com/zitadel/zitadel/cmd/tls"
|
cmd_tls "github.com/zitadel/zitadel/cmd/tls"
|
||||||
@ -35,6 +33,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/grpc/auth"
|
"github.com/zitadel/zitadel/internal/api/grpc/auth"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/session/v2"
|
"github.com/zitadel/zitadel/internal/api/grpc/session/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/settings/v2"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/system"
|
"github.com/zitadel/zitadel/internal/api/grpc/system"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/user/v2"
|
"github.com/zitadel/zitadel/internal/api/grpc/user/v2"
|
||||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||||
@ -339,6 +338,9 @@ func startAPIs(
|
|||||||
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries, permissionCheck)); err != nil {
|
if err := apis.RegisterService(ctx, session.CreateServer(commands, queries, permissionCheck)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := apis.RegisterService(ctx, settings.CreateServer(commands, queries, config.ExternalSecure)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader, login.IgnoreInstanceEndpoints...)
|
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader, login.IgnoreInstanceEndpoints...)
|
||||||
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
|
assetsCache := middleware.AssetsCacheInterceptor(config.AssetStorage.Cache.MaxAge, config.AssetStorage.Cache.SharedMaxAge)
|
||||||
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
|
apis.RegisterHandlerOnPrefix(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator(), store, queries, middleware.CallDurationHandler, instanceInterceptor.Handler, assetsCache.Handler, limitingAccessInterceptor.Handle))
|
||||||
@ -392,20 +394,11 @@ func startAPIs(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func reusePort(network, address string, conn syscall.RawConn) error {
|
|
||||||
return conn.Control(func(descriptor uintptr) {
|
|
||||||
err := syscall.SetsockoptInt(int(descriptor), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func listen(ctx context.Context, router *mux.Router, port uint16, tlsConfig *tls.Config, shutdown <-chan os.Signal) error {
|
func listen(ctx context.Context, router *mux.Router, port uint16, tlsConfig *tls.Config, shutdown <-chan os.Signal) error {
|
||||||
http2Server := &http2.Server{}
|
http2Server := &http2.Server{}
|
||||||
http1Server := &http.Server{Handler: h2c.NewHandler(router, http2Server), TLSConfig: tlsConfig}
|
http1Server := &http.Server{Handler: h2c.NewHandler(router, http2Server), TLSConfig: tlsConfig}
|
||||||
|
|
||||||
lc := &net.ListenConfig{Control: reusePort}
|
lc := listenConfig()
|
||||||
lis, err := lc.Listen(ctx, "tcp", fmt.Sprintf(":%d", port))
|
lis, err := lc.Listen(ctx, "tcp", fmt.Sprintf(":%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tcp listener on %d failed: %w", port, err)
|
return fmt.Errorf("tcp listener on %d failed: %w", port, err)
|
||||||
|
11
cmd/start/start_port.go
Normal file
11
cmd/start/start_port.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
//go:build !integration
|
||||||
|
|
||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listenConfig() *net.ListenConfig {
|
||||||
|
return &net.ListenConfig{}
|
||||||
|
}
|
25
cmd/start/start_port_integration.go
Normal file
25
cmd/start/start_port_integration.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package start
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listenConfig() *net.ListenConfig {
|
||||||
|
return &net.ListenConfig{
|
||||||
|
Control: reusePort,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func reusePort(network, address string, conn syscall.RawConn) error {
|
||||||
|
return conn.Control(func(descriptor uintptr) {
|
||||||
|
err := syscall.SetsockoptInt(int(descriptor), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -30,19 +30,23 @@
|
|||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<div class="app-specs cnsl-secondary-text">
|
<div class="app-specs cnsl-secondary-text">
|
||||||
<div class="row" *ngIf="isOIDC && method && method.responseType !== undefined">
|
<div class="row" *ngIf="isOIDC && method && method.responseType !== undefined">
|
||||||
<span>{{ 'APP.OIDC.RESPONSETYPE' | translate }}</span>
|
<span class="row-entry">{{ 'APP.OIDC.RESPONSETYPE' | translate }}</span>
|
||||||
<span>{{ 'APP.OIDC.RESPONSE.' + method.responseType.toString() | translate }}</span>
|
<span>{{ 'APP.OIDC.RESPONSE.' + method.responseType.toString() | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" *ngIf="isOIDC && method.grantType !== undefined">
|
<div class="row" *ngIf="isOIDC && method.grantType !== undefined">
|
||||||
<span>{{ 'APP.GRANT' | translate }}</span>
|
<span class="row-entry">{{ 'APP.GRANT' | translate }}</span>
|
||||||
<span>{{ 'APP.OIDC.GRANT.' + method.grantType.toString() | translate }}</span>
|
<span
|
||||||
|
><span class="space" *ngFor="let grant of method.grantType">{{
|
||||||
|
'APP.OIDC.GRANT.' + grant.toString() | translate
|
||||||
|
}}</span></span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" *ngIf="isOIDC && method.authMethod !== undefined">
|
<div class="row" *ngIf="isOIDC && method.authMethod !== undefined">
|
||||||
<span>{{ 'APP.AUTHMETHOD' | translate }}</span>
|
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
|
||||||
<span>{{ 'APP.OIDC.AUTHMETHOD.' + method.authMethod.toString() | translate }}</span>
|
<span>{{ 'APP.OIDC.AUTHMETHOD.' + method.authMethod.toString() | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" *ngIf="!isOIDC && method.apiAuthMethod !== undefined">
|
<div class="row" *ngIf="!isOIDC && method.apiAuthMethod !== undefined">
|
||||||
<span>{{ 'APP.AUTHMETHOD' | translate }}</span>
|
<span class="row-entry">{{ 'APP.AUTHMETHOD' | translate }}</span>
|
||||||
<span>{{ 'APP.API.AUTHMETHOD.' + method.apiAuthMethod.toString() | translate }}</span>
|
<span>{{ 'APP.API.AUTHMETHOD.' + method.apiAuthMethod.toString() | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -155,7 +155,11 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
:first-child {
|
.space {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-entry {
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -14,7 +14,7 @@ export interface RadioItemAuthType {
|
|||||||
prefix: string;
|
prefix: string;
|
||||||
background: string;
|
background: string;
|
||||||
responseType?: OIDCResponseType;
|
responseType?: OIDCResponseType;
|
||||||
grantType?: OIDCGrantType;
|
grantType?: OIDCGrantType[];
|
||||||
authMethod?: OIDCAuthMethodType;
|
authMethod?: OIDCAuthMethodType;
|
||||||
apiAuthMethod?: APIAuthMethodType;
|
apiAuthMethod?: APIAuthMethodType;
|
||||||
recommended?: boolean;
|
recommended?: boolean;
|
||||||
|
@ -58,13 +58,9 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- skip for native OIDC and SAML applications -->
|
<!-- skip for SAML applications -->
|
||||||
<mat-step
|
<mat-step
|
||||||
*ngIf="
|
*ngIf="appType?.value?.createType === AppCreateType.OIDC || appType?.value?.createType === AppCreateType.API"
|
||||||
(appType?.value?.createType === AppCreateType.OIDC &&
|
|
||||||
appType?.value.oidcAppType !== OIDCAppType.OIDC_APP_TYPE_NATIVE) ||
|
|
||||||
appType?.value?.createType === AppCreateType.API
|
|
||||||
"
|
|
||||||
[stepControl]="secondFormGroup"
|
[stepControl]="secondFormGroup"
|
||||||
[editable]="true"
|
[editable]="true"
|
||||||
>
|
>
|
||||||
@ -93,9 +89,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<!-- show redirect step only for OIDC apps -->
|
<!-- show redirect step only for OIDC apps -->
|
||||||
<mat-step *ngIf="appType?.value?.createType === AppCreateType.OIDC" [editable]="true">
|
<mat-step
|
||||||
|
*ngIf="appType?.value?.createType === AppCreateType.OIDC && authMethod?.value !== 'DEVICECODE'"
|
||||||
|
[editable]="true"
|
||||||
|
>
|
||||||
<ng-template matStepLabel>{{ 'APP.OIDC.REDIRECTSECTION' | translate }}</ng-template>
|
<ng-template matStepLabel>{{ 'APP.OIDC.REDIRECTSECTION' | translate }}</ng-template>
|
||||||
|
|
||||||
<p class="step-title">{{ 'APP.OIDC.REDIRECTTITLE' | translate }}</p>
|
<p class="step-title">{{ 'APP.OIDC.REDIRECTTITLE' | translate }}</p>
|
||||||
@ -431,7 +429,13 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content" *ngIf="formappType?.value?.createType === AppCreateType.OIDC">
|
<div
|
||||||
|
class="content"
|
||||||
|
*ngIf="
|
||||||
|
formappType?.value?.createType === AppCreateType.OIDC &&
|
||||||
|
!(oidcAppRequest.toObject().appType === OIDCAppType.OIDC_APP_TYPE_NATIVE && grantTypesListContainsOnlyDeviceCode)
|
||||||
|
"
|
||||||
|
>
|
||||||
<div class="formfield full-width">
|
<div class="formfield full-width">
|
||||||
<cnsl-redirect-uris
|
<cnsl-redirect-uris
|
||||||
class="redirect-section"
|
class="redirect-section"
|
||||||
|
@ -32,6 +32,7 @@ import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog
|
|||||||
import {
|
import {
|
||||||
BASIC_AUTH_METHOD,
|
BASIC_AUTH_METHOD,
|
||||||
CODE_METHOD,
|
CODE_METHOD,
|
||||||
|
DEVICE_CODE_METHOD,
|
||||||
getPartialConfigFromAuthMethod,
|
getPartialConfigFromAuthMethod,
|
||||||
IMPLICIT_METHOD,
|
IMPLICIT_METHOD,
|
||||||
PKCE_METHOD,
|
PKCE_METHOD,
|
||||||
@ -112,6 +113,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
{ type: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, checked: true, disabled: false },
|
{ type: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, checked: true, disabled: false },
|
||||||
{ type: OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT, checked: false, disabled: true },
|
{ type: OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT, checked: false, disabled: true },
|
||||||
{ type: OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN, checked: false, disabled: true },
|
{ type: OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN, checked: false, disabled: true },
|
||||||
|
{ type: OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE, checked: false, disabled: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||||
@ -163,7 +165,7 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
switch (this.appType?.value.oidcAppType) {
|
switch (this.appType?.value.oidcAppType) {
|
||||||
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
||||||
this.authMethods = [PKCE_METHOD];
|
this.authMethods = [PKCE_METHOD, DEVICE_CODE_METHOD];
|
||||||
|
|
||||||
// automatically set to PKCE and skip step
|
// automatically set to PKCE and skip step
|
||||||
this.oidcAppRequest.setResponseTypesList([OIDCResponseType.OIDC_RESPONSE_TYPE_CODE]);
|
this.oidcAppRequest.setResponseTypesList([OIDCResponseType.OIDC_RESPONSE_TYPE_CODE]);
|
||||||
@ -473,6 +475,13 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
return this.form.get('grantTypesList');
|
return this.form.get('grantTypesList');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get grantTypesListContainsOnlyDeviceCode(): boolean {
|
||||||
|
return (
|
||||||
|
this.oidcAppRequest.toObject().grantTypesList.length === 1 &&
|
||||||
|
this.oidcAppRequest.toObject().grantTypesList[0] === OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
get formappType(): AbstractControl | null {
|
get formappType(): AbstractControl | null {
|
||||||
return this.form.get('appType');
|
return this.form.get('appType');
|
||||||
}
|
}
|
||||||
@ -480,9 +489,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
get formMetadataUrl(): AbstractControl | null {
|
get formMetadataUrl(): AbstractControl | null {
|
||||||
return this.form.get('metadataUrl');
|
return this.form.get('metadataUrl');
|
||||||
}
|
}
|
||||||
// get formapplicationType(): AbstractControl | null {
|
|
||||||
// return this.form.get('applicationType');
|
|
||||||
// }
|
|
||||||
|
|
||||||
get authMethodType(): AbstractControl | null {
|
get authMethodType(): AbstractControl | null {
|
||||||
return this.form.get('authMethodType');
|
return this.form.get('authMethodType');
|
||||||
|
@ -46,6 +46,7 @@ import {
|
|||||||
BASIC_AUTH_METHOD,
|
BASIC_AUTH_METHOD,
|
||||||
CODE_METHOD,
|
CODE_METHOD,
|
||||||
CUSTOM_METHOD,
|
CUSTOM_METHOD,
|
||||||
|
DEVICE_CODE_METHOD,
|
||||||
getAuthMethodFromPartialConfig,
|
getAuthMethodFromPartialConfig,
|
||||||
getPartialConfigFromAuthMethod,
|
getPartialConfigFromAuthMethod,
|
||||||
IMPLICIT_METHOD,
|
IMPLICIT_METHOD,
|
||||||
@ -89,6 +90,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
public oidcGrantTypes: OIDCGrantType[] = [
|
public oidcGrantTypes: OIDCGrantType[] = [
|
||||||
OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
||||||
OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT,
|
OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT,
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE,
|
||||||
OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN,
|
OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN,
|
||||||
];
|
];
|
||||||
public oidcAppTypes: OIDCAppType[] = [
|
public oidcAppTypes: OIDCAppType[] = [
|
||||||
@ -274,6 +276,16 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
if (this.app.oidcConfig) {
|
if (this.app.oidcConfig) {
|
||||||
this.getAuthMethodOptions('OIDC');
|
this.getAuthMethodOptions('OIDC');
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.app.oidcConfig.grantTypesList.length === 1 &&
|
||||||
|
this.app.oidcConfig.grantTypesList[0] === OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE
|
||||||
|
) {
|
||||||
|
this.settingsList = [
|
||||||
|
{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' },
|
||||||
|
{ id: 'token', i18nKey: 'APP.TOKEN' },
|
||||||
|
{ id: 'urls', i18nKey: 'APP.URLS' },
|
||||||
|
];
|
||||||
|
} else {
|
||||||
this.settingsList = [
|
this.settingsList = [
|
||||||
{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' },
|
{ id: 'configuration', i18nKey: 'APP.CONFIGURATION' },
|
||||||
{ id: 'token', i18nKey: 'APP.TOKEN' },
|
{ id: 'token', i18nKey: 'APP.TOKEN' },
|
||||||
@ -281,6 +293,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
{ id: 'additional-origins', i18nKey: 'APP.ADDITIONALORIGINS' },
|
{ id: 'additional-origins', i18nKey: 'APP.ADDITIONALORIGINS' },
|
||||||
{ id: 'urls', i18nKey: 'APP.URLS' },
|
{ id: 'urls', i18nKey: 'APP.URLS' },
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: this.app.oidcConfig });
|
this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: this.app.oidcConfig });
|
||||||
this.currentAuthMethod = this.initialAuthMethod;
|
this.currentAuthMethod = this.initialAuthMethod;
|
||||||
@ -381,7 +394,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
if (type === 'OIDC') {
|
if (type === 'OIDC') {
|
||||||
switch (this.app?.oidcConfig?.appType) {
|
switch (this.app?.oidcConfig?.appType) {
|
||||||
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
case OIDCAppType.OIDC_APP_TYPE_NATIVE:
|
||||||
this.authMethods = [PKCE_METHOD, CUSTOM_METHOD];
|
this.authMethods = [PKCE_METHOD, DEVICE_CODE_METHOD, CUSTOM_METHOD];
|
||||||
break;
|
break;
|
||||||
case OIDCAppType.OIDC_APP_TYPE_WEB:
|
case OIDCAppType.OIDC_APP_TYPE_WEB:
|
||||||
this.authMethods = [PKCE_METHOD, CODE_METHOD, PK_JWT_METHOD, POST_METHOD];
|
this.authMethods = [PKCE_METHOD, CODE_METHOD, PK_JWT_METHOD, POST_METHOD];
|
||||||
|
@ -16,10 +16,11 @@ export const CODE_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'CODE',
|
prefix: 'CODE',
|
||||||
background: 'linear-gradient(40deg, rgb(25 105 143) 30%, rgb(23 95 129))',
|
background: 'linear-gradient(40deg, rgb(25 105 143) 30%, rgb(23 95 129))',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
|
||||||
recommended: false,
|
recommended: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PKCE_METHOD: RadioItemAuthType = {
|
export const PKCE_METHOD: RadioItemAuthType = {
|
||||||
key: 'PKCE',
|
key: 'PKCE',
|
||||||
titleI18nKey: 'APP.AUTHMETHODS.PKCE.TITLE',
|
titleI18nKey: 'APP.AUTHMETHODS.PKCE.TITLE',
|
||||||
@ -28,10 +29,11 @@ export const PKCE_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'PKCE',
|
prefix: 'PKCE',
|
||||||
background: 'linear-gradient(40deg, #059669 30%, #047857)',
|
background: 'linear-gradient(40deg, #059669 30%, #047857)',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
recommended: true,
|
recommended: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const POST_METHOD: RadioItemAuthType = {
|
export const POST_METHOD: RadioItemAuthType = {
|
||||||
key: 'POST',
|
key: 'POST',
|
||||||
titleI18nKey: 'APP.AUTHMETHODS.POST.TITLE',
|
titleI18nKey: 'APP.AUTHMETHODS.POST.TITLE',
|
||||||
@ -40,10 +42,11 @@ export const POST_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'POST',
|
prefix: 'POST',
|
||||||
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
||||||
notRecommended: true,
|
notRecommended: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PK_JWT_METHOD: RadioItemAuthType = {
|
export const PK_JWT_METHOD: RadioItemAuthType = {
|
||||||
key: 'PK_JWT',
|
key: 'PK_JWT',
|
||||||
titleI18nKey: 'APP.AUTHMETHODS.PK_JWT.TITLE',
|
titleI18nKey: 'APP.AUTHMETHODS.PK_JWT.TITLE',
|
||||||
@ -52,11 +55,12 @@ export const PK_JWT_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'JWT',
|
prefix: 'JWT',
|
||||||
background: 'linear-gradient(40deg, rgb(70 77 145) 30%, rgb(58 65 124))',
|
background: 'linear-gradient(40deg, rgb(70 77 145) 30%, rgb(58 65 124))',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
||||||
apiAuthMethod: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
apiAuthMethod: APIAuthMethodType.API_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT,
|
||||||
// recommended: true,
|
// recommended: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BASIC_AUTH_METHOD: RadioItemAuthType = {
|
export const BASIC_AUTH_METHOD: RadioItemAuthType = {
|
||||||
key: 'BASIC',
|
key: 'BASIC',
|
||||||
titleI18nKey: 'APP.AUTHMETHODS.BASIC.TITLE',
|
titleI18nKey: 'APP.AUTHMETHODS.BASIC.TITLE',
|
||||||
@ -65,7 +69,7 @@ export const BASIC_AUTH_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'BASIC',
|
prefix: 'BASIC',
|
||||||
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
||||||
apiAuthMethod: APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC,
|
apiAuthMethod: APIAuthMethodType.API_AUTH_METHOD_TYPE_BASIC,
|
||||||
};
|
};
|
||||||
@ -78,11 +82,24 @@ export const IMPLICIT_METHOD: RadioItemAuthType = {
|
|||||||
prefix: 'IMP',
|
prefix: 'IMP',
|
||||||
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
background: 'linear-gradient(40deg, #c53b3b 30%, rgb(169 51 51))',
|
||||||
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_ID_TOKEN,
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_ID_TOKEN,
|
||||||
grantType: OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT,
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_IMPLICIT],
|
||||||
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
notRecommended: true,
|
notRecommended: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEVICE_CODE_METHOD: RadioItemAuthType = {
|
||||||
|
key: 'DEVICECODE',
|
||||||
|
titleI18nKey: 'APP.AUTHMETHODS.DEVICECODE.TITLE',
|
||||||
|
descI18nKey: 'APP.AUTHMETHODS.DEVICECODE.DESCRIPTION',
|
||||||
|
disabled: false,
|
||||||
|
prefix: 'DEVICECODE',
|
||||||
|
background: 'linear-gradient(40deg, rgb(56 189 248) 30%, rgb(14 165 233))',
|
||||||
|
responseType: OIDCResponseType.OIDC_RESPONSE_TYPE_CODE,
|
||||||
|
grantType: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE],
|
||||||
|
authMethod: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_BASIC,
|
||||||
|
recommended: false,
|
||||||
|
};
|
||||||
|
|
||||||
export const CUSTOM_METHOD: RadioItemAuthType = {
|
export const CUSTOM_METHOD: RadioItemAuthType = {
|
||||||
key: 'CUSTOM',
|
key: 'CUSTOM',
|
||||||
titleI18nKey: 'APP.AUTHMETHODS.CUSTOM.TITLE',
|
titleI18nKey: 'APP.AUTHMETHODS.CUSTOM.TITLE',
|
||||||
@ -112,6 +129,15 @@ export function getPartialConfigFromAuthMethod(authMethod: string):
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
|
case DEVICE_CODE_METHOD.key:
|
||||||
|
config = {
|
||||||
|
oidc: {
|
||||||
|
responseTypesList: [OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
|
grantTypesList: [OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE],
|
||||||
|
authMethodType: OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return config;
|
||||||
case PKCE_METHOD.key:
|
case PKCE_METHOD.key:
|
||||||
config = {
|
config = {
|
||||||
oidc: {
|
oidc: {
|
||||||
@ -211,6 +237,38 @@ export function getAuthMethodFromPartialConfig(config: {
|
|||||||
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_POST,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const deviceCode = JSON.stringify([
|
||||||
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
|
[OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE],
|
||||||
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const deviceCodeWithCode = JSON.stringify([
|
||||||
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
|
[
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE,
|
||||||
|
// OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN,
|
||||||
|
],
|
||||||
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const deviceCodeWithCodeAndRefresh = JSON.stringify([
|
||||||
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
|
[
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE,
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE,
|
||||||
|
OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN,
|
||||||
|
],
|
||||||
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const deviceCodeWithRefresh = JSON.stringify([
|
||||||
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
|
[OIDCGrantType.OIDC_GRANT_TYPE_DEVICE_CODE, OIDCGrantType.OIDC_GRANT_TYPE_REFRESH_TOKEN],
|
||||||
|
OIDCAuthMethodType.OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
]);
|
||||||
|
|
||||||
const pkjwt = JSON.stringify([
|
const pkjwt = JSON.stringify([
|
||||||
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
[OIDCResponseType.OIDC_RESPONSE_TYPE_CODE],
|
||||||
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
[OIDCGrantType.OIDC_GRANT_TYPE_AUTHORIZATION_CODE],
|
||||||
@ -245,6 +303,15 @@ export function getAuthMethodFromPartialConfig(config: {
|
|||||||
case postWithRefresh:
|
case postWithRefresh:
|
||||||
return POST_METHOD.key;
|
return POST_METHOD.key;
|
||||||
|
|
||||||
|
case deviceCode:
|
||||||
|
return DEVICE_CODE_METHOD.key;
|
||||||
|
case deviceCodeWithCode:
|
||||||
|
return DEVICE_CODE_METHOD.key;
|
||||||
|
case deviceCodeWithRefresh:
|
||||||
|
return DEVICE_CODE_METHOD.key;
|
||||||
|
case deviceCodeWithCodeAndRefresh:
|
||||||
|
return DEVICE_CODE_METHOD.key;
|
||||||
|
|
||||||
case pkjwt:
|
case pkjwt:
|
||||||
return PK_JWT_METHOD.key;
|
return PK_JWT_METHOD.key;
|
||||||
case pkjwtWithRefresh:
|
case pkjwtWithRefresh:
|
||||||
|
@ -1965,7 +1965,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Authorization Code",
|
"0": "Authorization Code",
|
||||||
"1": "Implicit",
|
"1": "Implicit",
|
||||||
"2": "Refresh Token"
|
"2": "Refresh Token",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2056,6 +2057,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "Erhalte die Token direkt vom authorize Endpoint"
|
"DESCRIPTION": "Erhalte die Token direkt vom authorize Endpoint"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Autorisieren Sie das Gerät auf einem Computer oder Smartphone."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Custom",
|
"TITLE": "Custom",
|
||||||
"DESCRIPTION": "Deine Konfiguration entspricht keiner anderen Option."
|
"DESCRIPTION": "Deine Konfiguration entspricht keiner anderen Option."
|
||||||
|
@ -1962,7 +1962,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Authorization Code",
|
"0": "Authorization Code",
|
||||||
"1": "Implicit",
|
"1": "Implicit",
|
||||||
"2": "Refresh Token"
|
"2": "Refresh Token",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2053,6 +2054,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "Get the tokens directly from the authorization endpoint"
|
"DESCRIPTION": "Get the tokens directly from the authorization endpoint"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Authorize the device on a computer or smartphone."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Custom",
|
"TITLE": "Custom",
|
||||||
"DESCRIPTION": "Your setting doesn't correspond to any other option."
|
"DESCRIPTION": "Your setting doesn't correspond to any other option."
|
||||||
|
@ -1962,7 +1962,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Código de autorización",
|
"0": "Código de autorización",
|
||||||
"1": "Implícito",
|
"1": "Implícito",
|
||||||
"2": "Token de refresco"
|
"2": "Token de refresco",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Básico",
|
"0": "Básico",
|
||||||
@ -2053,6 +2054,10 @@
|
|||||||
"TITLE": "Implícita",
|
"TITLE": "Implícita",
|
||||||
"DESCRIPTION": "Obtén los tokens directamente del endpoint de autorización"
|
"DESCRIPTION": "Obtén los tokens directamente del endpoint de autorización"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Autorizar el dispositivo en una computadora o teléfono."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Personalizada",
|
"TITLE": "Personalizada",
|
||||||
"DESCRIPTION": "Tu configuración no se corresponde con alguna de las otras opciones."
|
"DESCRIPTION": "Tu configuración no se corresponde con alguna de las otras opciones."
|
||||||
|
@ -1966,7 +1966,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Code d'autorisation",
|
"0": "Code d'autorisation",
|
||||||
"1": "Implicite",
|
"1": "Implicite",
|
||||||
"2": "Rafraîchir le jeton"
|
"2": "Rafraîchir le jeton",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2045,6 +2046,10 @@
|
|||||||
"TITLE": "Implicite",
|
"TITLE": "Implicite",
|
||||||
"DESCRIPTION": "Obtenir les jetons directement à partir du point final d'autorisation"
|
"DESCRIPTION": "Obtenir les jetons directement à partir du point final d'autorisation"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Autoriser l'appareil sur un ordinateur ou un smartphone."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Personnalisé",
|
"TITLE": "Personnalisé",
|
||||||
"DESCRIPTION": "Votre paramètre ne correspond à aucune autre option."
|
"DESCRIPTION": "Votre paramètre ne correspond à aucune autre option."
|
||||||
|
@ -1967,7 +1967,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Authorization Code",
|
"0": "Authorization Code",
|
||||||
"1": "Implicit",
|
"1": "Implicit",
|
||||||
"2": "Refresh Token"
|
"2": "Refresh Token",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2058,6 +2059,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "Ottenere i token direttamente dall'endpoint di autorizzazione"
|
"DESCRIPTION": "Ottenere i token direttamente dall'endpoint di autorizzazione"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Autorizza il dispositivo su un computer o uno smartphone."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Custom",
|
"TITLE": "Custom",
|
||||||
"DESCRIPTION": "La tua impostazione non corrisponde a nessun'altra opzione."
|
"DESCRIPTION": "La tua impostazione non corrisponde a nessun'altra opzione."
|
||||||
|
@ -1957,7 +1957,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Authorization Code",
|
"0": "Authorization Code",
|
||||||
"1": "Implicit",
|
"1": "Implicit",
|
||||||
"2": "Refresh Token"
|
"2": "Refresh Token",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2048,6 +2049,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "認証エンドポイントから直接トークンを取得します。"
|
"DESCRIPTION": "認証エンドポイントから直接トークンを取得します。"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "コンピューターまたはスマートフォンでデバイスを認証します。"
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Custom",
|
"TITLE": "Custom",
|
||||||
"DESCRIPTION": "設定は他のオプションに対応していません。"
|
"DESCRIPTION": "設定は他のオプションに対応していません。"
|
||||||
|
@ -1966,7 +1966,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Kod autoryzacyjny",
|
"0": "Kod autoryzacyjny",
|
||||||
"1": "Implicite",
|
"1": "Implicite",
|
||||||
"2": "Token odświeżający"
|
"2": "Token odświeżający",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Podstawowy",
|
"0": "Podstawowy",
|
||||||
@ -2057,6 +2058,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "Pobierz tokeny bezpośrednio z punktu autoryzacyjnego"
|
"DESCRIPTION": "Pobierz tokeny bezpośrednio z punktu autoryzacyjnego"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "Autoryzuj urządzenie na komputerze lub smartfonie."
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Niestandardowy",
|
"TITLE": "Niestandardowy",
|
||||||
"DESCRIPTION": "Twoje ustawienie nie odpowiada żadnej innej opcji."
|
"DESCRIPTION": "Twoje ustawienie nie odpowiada żadnej innej opcji."
|
||||||
|
@ -1965,7 +1965,8 @@
|
|||||||
"GRANT": {
|
"GRANT": {
|
||||||
"0": "Authorization Code",
|
"0": "Authorization Code",
|
||||||
"1": "Implicit",
|
"1": "Implicit",
|
||||||
"2": "Refresh Token"
|
"2": "Refresh Token",
|
||||||
|
"3": "Device Code"
|
||||||
},
|
},
|
||||||
"AUTHMETHOD": {
|
"AUTHMETHOD": {
|
||||||
"0": "Basic",
|
"0": "Basic",
|
||||||
@ -2044,6 +2045,10 @@
|
|||||||
"TITLE": "Implicit",
|
"TITLE": "Implicit",
|
||||||
"DESCRIPTION": "直接从授权端点获取令牌"
|
"DESCRIPTION": "直接从授权端点获取令牌"
|
||||||
},
|
},
|
||||||
|
"DEVICECODE": {
|
||||||
|
"TITLE": "Device Code",
|
||||||
|
"DESCRIPTION": "在计算机或智能手机上授权设备。"
|
||||||
|
},
|
||||||
"CUSTOM": {
|
"CUSTOM": {
|
||||||
"TITLE": "Custom",
|
"TITLE": "Custom",
|
||||||
"DESCRIPTION": "您的设置与任何其他选项都不对应。"
|
"DESCRIPTION": "您的设置与任何其他选项都不对应。"
|
||||||
|
@ -273,6 +273,13 @@ module.exports = {
|
|||||||
sidebarOptions: {
|
sidebarOptions: {
|
||||||
groupPathsBy: "tag",
|
groupPathsBy: "tag",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
specPath: ".artifacts/openapi/zitadel/settings/v2alpha/settings_service.swagger.json",
|
||||||
|
outputDir: "docs/apis/settings_service",
|
||||||
|
sidebarOptions: {
|
||||||
|
groupPathsBy: "tag",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -426,6 +426,20 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
items: require("./docs/apis/session_service/sidebar.js"),
|
items: require("./docs/apis/session_service/sidebar.js"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "category",
|
||||||
|
label: "Settings Lifecycle (Alpha)",
|
||||||
|
link: {
|
||||||
|
type: "generated-index",
|
||||||
|
title: "Settings Service API (Alpha)",
|
||||||
|
slug: "/apis/settings_service",
|
||||||
|
description:
|
||||||
|
"This API is intended to manage settings in a ZITADEL instance.\n"+
|
||||||
|
"\n"+
|
||||||
|
"This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.",
|
||||||
|
},
|
||||||
|
items: require("./docs/apis/settings_service/sidebar.js"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "Assets",
|
label: "Assets",
|
||||||
|
@ -2,7 +2,8 @@ import { Apps, ensureProjectExists, ensureProjectResourceDoesntExist } from '../
|
|||||||
import { Context } from 'support/commands';
|
import { Context } from 'support/commands';
|
||||||
|
|
||||||
const testProjectName = 'e2eprojectapplication';
|
const testProjectName = 'e2eprojectapplication';
|
||||||
const testAppName = 'e2eappundertest';
|
const testPKCEAppName = 'e2eapppkcetest';
|
||||||
|
const testDEVICECODEAppName = 'e2eappdevicecodetest';
|
||||||
|
|
||||||
describe('applications', () => {
|
describe('applications', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -17,15 +18,15 @@ describe('applications', () => {
|
|||||||
beforeEach(`ensure it doesn't exist already`, () => {
|
beforeEach(`ensure it doesn't exist already`, () => {
|
||||||
cy.get<Context>('@ctx').then((ctx) => {
|
cy.get<Context>('@ctx').then((ctx) => {
|
||||||
cy.get<string>('@projectId').then((projectId) => {
|
cy.get<string>('@projectId').then((projectId) => {
|
||||||
ensureProjectResourceDoesntExist(ctx.api, projectId, Apps, testAppName);
|
ensureProjectResourceDoesntExist(ctx.api, projectId, Apps, testPKCEAppName);
|
||||||
cy.visit(`/projects/${projectId}`);
|
cy.visit(`/projects/${projectId}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('add app', () => {
|
it('add web pkce app', () => {
|
||||||
cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
|
cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
|
||||||
cy.get('[formcontrolname="name"]').focus().type(testAppName);
|
cy.get('[formcontrolname="name"]').focus().type(testPKCEAppName);
|
||||||
cy.get('[for="WEB"]').click();
|
cy.get('[for="WEB"]').click();
|
||||||
cy.get('[data-e2e="continue-button-nameandtype"]').click();
|
cy.get('[data-e2e="continue-button-nameandtype"]').click();
|
||||||
cy.get('[for="PKCE"]').should('be.visible').click();
|
cy.get('[for="PKCE"]').should('be.visible').click();
|
||||||
@ -43,6 +44,33 @@ describe('applications', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('add native device code app', () => {
|
||||||
|
beforeEach(`ensure it doesn't exist already`, () => {
|
||||||
|
cy.get<Context>('@ctx').then((ctx) => {
|
||||||
|
cy.get<string>('@projectId').then((projectId) => {
|
||||||
|
ensureProjectResourceDoesntExist(ctx.api, projectId, Apps, testDEVICECODEAppName);
|
||||||
|
cy.visit(`/projects/${projectId}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('add device code app', () => {
|
||||||
|
cy.get('[data-e2e="app-card-add"]').should('be.visible').click();
|
||||||
|
cy.get('[formcontrolname="name"]').focus().type(testDEVICECODEAppName);
|
||||||
|
cy.get('[for="N"]').click();
|
||||||
|
cy.get('[data-e2e="continue-button-nameandtype"]').click();
|
||||||
|
cy.get('[for="DEVICECODE"]').should('be.visible').click();
|
||||||
|
cy.get('[data-e2e="continue-button-authmethod"]').click();
|
||||||
|
cy.get('[data-e2e="create-button"]').click();
|
||||||
|
cy.get('[id*=overlay]').should('exist');
|
||||||
|
cy.shouldConfirmSuccess();
|
||||||
|
const expectClientId = new RegExp(`^.*[0-9]+\\@${testProjectName}.*$`);
|
||||||
|
cy.get('[data-e2e="client-id-copy"]').click();
|
||||||
|
cy.contains('[data-e2e="client-id"]', expectClientId);
|
||||||
|
cy.clipboardMatches(expectClientId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('edit app', () => {
|
describe('edit app', () => {
|
||||||
it('should configure an application to enable dev mode');
|
it('should configure an application to enable dev mode');
|
||||||
it('should configure an application to put user roles and info inside id token');
|
it('should configure an application to put user roles and info inside id token');
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package object
|
package object
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha"
|
object "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha"
|
||||||
@ -36,3 +39,13 @@ func ListQueryToQuery(query *object.ListQuery) (offset, limit uint64, asc bool)
|
|||||||
}
|
}
|
||||||
return query.Offset, uint64(query.Limit), query.Asc
|
return query.Offset, uint64(query.Limit), query.Asc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ResourceOwnerFromReq(ctx context.Context, req *object.RequestContext) string {
|
||||||
|
if req.GetInstance() {
|
||||||
|
return authz.GetInstance(ctx).InstanceID()
|
||||||
|
}
|
||||||
|
if req.GetOrgId() != "" {
|
||||||
|
return req.GetOrgId()
|
||||||
|
}
|
||||||
|
return authz.GetCtxData(ctx).OrgID
|
||||||
|
}
|
||||||
|
57
internal/api/grpc/settings/v2/server.go
Normal file
57
internal/api/grpc/settings/v2/server.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/assets"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||||
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ settings.SettingsServiceServer = (*Server)(nil)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
settings.UnimplementedSettingsServiceServer
|
||||||
|
command *command.Commands
|
||||||
|
query *query.Queries
|
||||||
|
assetsAPIDomain func(context.Context) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct{}
|
||||||
|
|
||||||
|
func CreateServer(
|
||||||
|
command *command.Commands,
|
||||||
|
query *query.Queries,
|
||||||
|
externalSecure bool,
|
||||||
|
) *Server {
|
||||||
|
return &Server{
|
||||||
|
command: command,
|
||||||
|
query: query,
|
||||||
|
assetsAPIDomain: assets.AssetAPI(externalSecure),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||||
|
settings.RegisterSettingsServiceServer(grpcServer, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AppName() string {
|
||||||
|
return settings.SettingsService_ServiceDesc.ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) MethodPrefix() string {
|
||||||
|
return settings.SettingsService_ServiceDesc.ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||||
|
return settings.SettingsService_AuthMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||||
|
return settings.RegisterSettingsServiceHandler
|
||||||
|
}
|
129
internal/api/grpc/settings/v2/settings.go
Normal file
129
internal/api/grpc/settings/v2/settings.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/text"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
object_pb "github.com/zitadel/zitadel/pkg/grpc/object/v2alpha"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) GetLoginSettings(ctx context.Context, req *settings.GetLoginSettingsRequest) (*settings.GetLoginSettingsResponse, error) {
|
||||||
|
current, err := s.query.LoginPolicyByID(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetLoginSettingsResponse{
|
||||||
|
Settings: loginSettingsToPb(current),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.OrgID,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetPasswordComplexitySettings(ctx context.Context, req *settings.GetPasswordComplexitySettingsRequest) (*settings.GetPasswordComplexitySettingsResponse, error) {
|
||||||
|
current, err := s.query.PasswordComplexityPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetPasswordComplexitySettingsResponse{
|
||||||
|
Settings: passwordSettingsToPb(current),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.ResourceOwner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetBrandingSettings(ctx context.Context, req *settings.GetBrandingSettingsRequest) (*settings.GetBrandingSettingsResponse, error) {
|
||||||
|
current, err := s.query.ActiveLabelPolicyByOrg(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetBrandingSettingsResponse{
|
||||||
|
Settings: brandingSettingsToPb(current, s.assetsAPIDomain(ctx)),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.ResourceOwner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetDomainSettings(ctx context.Context, req *settings.GetDomainSettingsRequest) (*settings.GetDomainSettingsResponse, error) {
|
||||||
|
current, err := s.query.DomainPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetDomainSettingsResponse{
|
||||||
|
Settings: domainSettingsToPb(current),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.ResourceOwner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetLegalAndSupportSettings(ctx context.Context, req *settings.GetLegalAndSupportSettingsRequest) (*settings.GetLegalAndSupportSettingsResponse, error) {
|
||||||
|
current, err := s.query.PrivacyPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetLegalAndSupportSettingsResponse{
|
||||||
|
Settings: legalAndSupportSettingsToPb(current),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.ResourceOwner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetLockoutSettings(ctx context.Context, req *settings.GetLockoutSettingsRequest) (*settings.GetLockoutSettingsResponse, error) {
|
||||||
|
current, err := s.query.LockoutPolicyByOrg(ctx, true, object.ResourceOwnerFromReq(ctx, req.GetCtx()), false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &settings.GetLockoutSettingsResponse{
|
||||||
|
Settings: lockoutSettingsToPb(current),
|
||||||
|
Details: &object_pb.Details{
|
||||||
|
Sequence: current.Sequence,
|
||||||
|
ChangeDate: timestamppb.New(current.ChangeDate),
|
||||||
|
ResourceOwner: current.ResourceOwner,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetActiveIdentityProviders(ctx context.Context, req *settings.GetActiveIdentityProvidersRequest) (*settings.GetActiveIdentityProvidersResponse, error) {
|
||||||
|
links, err := s.query.IDPLoginPolicyLinks(ctx, object.ResourceOwnerFromReq(ctx, req.GetCtx()), &query.IDPLoginPolicyLinksSearchQuery{}, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &settings.GetActiveIdentityProvidersResponse{
|
||||||
|
Details: object.ToListDetails(links.SearchResponse),
|
||||||
|
IdentityProviders: identityProvidersToPb(links.Links),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetGeneralSettings(ctx context.Context, _ *settings.GetGeneralSettingsRequest) (*settings.GetGeneralSettingsResponse, error) {
|
||||||
|
langs, err := s.query.Languages(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
instance := authz.GetInstance(ctx)
|
||||||
|
return &settings.GetGeneralSettingsResponse{
|
||||||
|
SupportedLanguages: text.LanguageTagsToStrings(langs),
|
||||||
|
DefaultOrgId: instance.DefaultOrganisationID(),
|
||||||
|
DefaultLanguage: instance.DefaultLanguage().String(),
|
||||||
|
}, nil
|
||||||
|
}
|
189
internal/api/grpc/settings/v2/settings_converter.go
Normal file
189
internal/api/grpc/settings/v2/settings_converter.go
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: ?
|
||||||
|
func loginSettingsToPb(current *query.LoginPolicy) *settings.LoginSettings {
|
||||||
|
multi := make([]settings.MultiFactorType, len(current.MultiFactors))
|
||||||
|
for i, typ := range current.MultiFactors {
|
||||||
|
multi[i] = multiFactorTypeToPb(typ)
|
||||||
|
}
|
||||||
|
second := make([]settings.SecondFactorType, len(current.SecondFactors))
|
||||||
|
for i, typ := range current.SecondFactors {
|
||||||
|
second[i] = secondFactorTypeToPb(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &settings.LoginSettings{
|
||||||
|
AllowUsernamePassword: current.AllowUsernamePassword,
|
||||||
|
AllowRegister: current.AllowRegister,
|
||||||
|
AllowExternalIdp: current.AllowExternalIDPs,
|
||||||
|
ForceMfa: current.ForceMFA,
|
||||||
|
PasskeysType: passkeysTypeToPb(current.PasswordlessType),
|
||||||
|
HidePasswordReset: current.HidePasswordReset,
|
||||||
|
IgnoreUnknownUsernames: current.IgnoreUnknownUsernames,
|
||||||
|
AllowDomainDiscovery: current.AllowDomainDiscovery,
|
||||||
|
DisableLoginWithEmail: current.DisableLoginWithEmail,
|
||||||
|
DisableLoginWithPhone: current.DisableLoginWithPhone,
|
||||||
|
DefaultRedirectUri: current.DefaultRedirectURI,
|
||||||
|
PasswordCheckLifetime: durationpb.New(current.PasswordCheckLifetime),
|
||||||
|
ExternalLoginCheckLifetime: durationpb.New(current.ExternalLoginCheckLifetime),
|
||||||
|
MfaInitSkipLifetime: durationpb.New(current.MFAInitSkipLifetime),
|
||||||
|
SecondFactorCheckLifetime: durationpb.New(current.SecondFactorCheckLifetime),
|
||||||
|
MultiFactorCheckLifetime: durationpb.New(current.MultiFactorCheckLifetime),
|
||||||
|
SecondFactors: second,
|
||||||
|
MultiFactors: multi,
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDefaultToResourceOwnerTypePb(isDefault bool) settings.ResourceOwnerType {
|
||||||
|
if isDefault {
|
||||||
|
return settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE
|
||||||
|
}
|
||||||
|
return settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_ORG
|
||||||
|
}
|
||||||
|
|
||||||
|
func passkeysTypeToPb(passwordlessType domain.PasswordlessType) settings.PasskeysType {
|
||||||
|
switch passwordlessType {
|
||||||
|
case domain.PasswordlessTypeAllowed:
|
||||||
|
return settings.PasskeysType_PASSKEYS_TYPE_ALLOWED
|
||||||
|
case domain.PasswordlessTypeNotAllowed:
|
||||||
|
return settings.PasskeysType_PASSKEYS_TYPE_NOT_ALLOWED
|
||||||
|
default:
|
||||||
|
return settings.PasskeysType_PASSKEYS_TYPE_NOT_ALLOWED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func secondFactorTypeToPb(secondFactorType domain.SecondFactorType) settings.SecondFactorType {
|
||||||
|
switch secondFactorType {
|
||||||
|
case domain.SecondFactorTypeOTP:
|
||||||
|
return settings.SecondFactorType_SECOND_FACTOR_TYPE_OTP
|
||||||
|
case domain.SecondFactorTypeU2F:
|
||||||
|
return settings.SecondFactorType_SECOND_FACTOR_TYPE_U2F
|
||||||
|
case domain.SecondFactorTypeUnspecified:
|
||||||
|
return settings.SecondFactorType_SECOND_FACTOR_TYPE_UNSPECIFIED
|
||||||
|
default:
|
||||||
|
return settings.SecondFactorType_SECOND_FACTOR_TYPE_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiFactorTypeToPb(typ domain.MultiFactorType) settings.MultiFactorType {
|
||||||
|
switch typ {
|
||||||
|
case domain.MultiFactorTypeU2FWithPIN:
|
||||||
|
return settings.MultiFactorType_MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION
|
||||||
|
case domain.MultiFactorTypeUnspecified:
|
||||||
|
return settings.MultiFactorType_MULTI_FACTOR_TYPE_UNSPECIFIED
|
||||||
|
default:
|
||||||
|
return settings.MultiFactorType_MULTI_FACTOR_TYPE_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func passwordSettingsToPb(current *query.PasswordComplexityPolicy) *settings.PasswordComplexitySettings {
|
||||||
|
return &settings.PasswordComplexitySettings{
|
||||||
|
MinLength: current.MinLength,
|
||||||
|
RequiresUppercase: current.HasUppercase,
|
||||||
|
RequiresLowercase: current.HasLowercase,
|
||||||
|
RequiresNumber: current.HasNumber,
|
||||||
|
RequiresSymbol: current.HasSymbol,
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func brandingSettingsToPb(current *query.LabelPolicy, assetPrefix string) *settings.BrandingSettings {
|
||||||
|
return &settings.BrandingSettings{
|
||||||
|
LightTheme: themeToPb(current.Light, assetPrefix, current.ResourceOwner),
|
||||||
|
DarkTheme: themeToPb(current.Dark, assetPrefix, current.ResourceOwner),
|
||||||
|
FontUrl: domain.AssetURL(assetPrefix, current.ResourceOwner, current.FontURL),
|
||||||
|
DisableWatermark: current.WatermarkDisabled,
|
||||||
|
HideLoginNameSuffix: current.HideLoginNameSuffix,
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func themeToPb(theme query.Theme, assetPrefix, resourceOwner string) *settings.Theme {
|
||||||
|
return &settings.Theme{
|
||||||
|
PrimaryColor: theme.PrimaryColor,
|
||||||
|
BackgroundColor: theme.BackgroundColor,
|
||||||
|
FontColor: theme.FontColor,
|
||||||
|
WarnColor: theme.WarnColor,
|
||||||
|
LogoUrl: domain.AssetURL(assetPrefix, resourceOwner, theme.LogoURL),
|
||||||
|
IconUrl: domain.AssetURL(assetPrefix, resourceOwner, theme.IconURL),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func domainSettingsToPb(current *query.DomainPolicy) *settings.DomainSettings {
|
||||||
|
return &settings.DomainSettings{
|
||||||
|
LoginNameIncludesDomain: current.UserLoginMustBeDomain,
|
||||||
|
RequireOrgDomainVerification: current.ValidateOrgDomains,
|
||||||
|
SmtpSenderAddressMatchesInstanceDomain: current.SMTPSenderAddressMatchesInstanceDomain,
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func legalAndSupportSettingsToPb(current *query.PrivacyPolicy) *settings.LegalAndSupportSettings {
|
||||||
|
return &settings.LegalAndSupportSettings{
|
||||||
|
TosLink: current.TOSLink,
|
||||||
|
PrivacyPolicyLink: current.PrivacyLink,
|
||||||
|
HelpLink: current.HelpLink,
|
||||||
|
SupportEmail: string(current.SupportEmail),
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lockoutSettingsToPb(current *query.LockoutPolicy) *settings.LockoutSettings {
|
||||||
|
return &settings.LockoutSettings{
|
||||||
|
MaxPasswordAttempts: current.MaxPasswordAttempts,
|
||||||
|
ResourceOwnerType: isDefaultToResourceOwnerTypePb(current.IsDefault),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func identityProvidersToPb(idps []*query.IDPLoginPolicyLink) []*settings.IdentityProvider {
|
||||||
|
providers := make([]*settings.IdentityProvider, len(idps))
|
||||||
|
for i, idp := range idps {
|
||||||
|
providers[i] = identityProviderToPb(idp)
|
||||||
|
}
|
||||||
|
return providers
|
||||||
|
}
|
||||||
|
|
||||||
|
func identityProviderToPb(idp *query.IDPLoginPolicyLink) *settings.IdentityProvider {
|
||||||
|
return &settings.IdentityProvider{
|
||||||
|
Id: idp.IDPID,
|
||||||
|
Name: domain.IDPName(idp.IDPName, idp.IDPType),
|
||||||
|
Type: idpTypeToPb(idp.IDPType),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func idpTypeToPb(idpType domain.IDPType) settings.IdentityProviderType {
|
||||||
|
switch idpType {
|
||||||
|
case domain.IDPTypeUnspecified:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_UNSPECIFIED
|
||||||
|
case domain.IDPTypeOIDC:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OIDC
|
||||||
|
case domain.IDPTypeJWT:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_JWT
|
||||||
|
case domain.IDPTypeOAuth:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OAUTH
|
||||||
|
case domain.IDPTypeLDAP:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_LDAP
|
||||||
|
case domain.IDPTypeAzureAD:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_AZURE_AD
|
||||||
|
case domain.IDPTypeGitHub:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB
|
||||||
|
case domain.IDPTypeGitHubEnterprise:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB_ES
|
||||||
|
case domain.IDPTypeGitLab:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITLAB
|
||||||
|
case domain.IDPTypeGitLabSelfHosted:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITLAB_SELF_HOSTED
|
||||||
|
case domain.IDPTypeGoogle:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GOOGLE
|
||||||
|
default:
|
||||||
|
return settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
461
internal/api/grpc/settings/v2/settings_converter_test.go
Normal file
461
internal/api/grpc/settings/v2/settings_converter_test.go
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ignoreMessageTypes = map[protoreflect.FullName]bool{
|
||||||
|
"google.protobuf.Duration": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// allFieldsSet recusively checks if all values in a message
|
||||||
|
// have a non-zero value.
|
||||||
|
func allFieldsSet(t testing.TB, msg protoreflect.Message) {
|
||||||
|
md := msg.Descriptor()
|
||||||
|
name := md.FullName()
|
||||||
|
if ignoreMessageTypes[name] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := md.Fields()
|
||||||
|
|
||||||
|
for i := 0; i < fields.Len(); i++ {
|
||||||
|
fd := fields.Get(i)
|
||||||
|
if !msg.Has(fd) {
|
||||||
|
t.Errorf("not all fields set in %q, missing %q", name, fd.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fd.Kind() == protoreflect.MessageKind {
|
||||||
|
allFieldsSet(t, msg.Get(fd).Message())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_loginSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.LoginPolicy{
|
||||||
|
AllowUsernamePassword: true,
|
||||||
|
AllowRegister: true,
|
||||||
|
AllowExternalIDPs: true,
|
||||||
|
ForceMFA: true,
|
||||||
|
PasswordlessType: domain.PasswordlessTypeAllowed,
|
||||||
|
HidePasswordReset: true,
|
||||||
|
IgnoreUnknownUsernames: true,
|
||||||
|
AllowDomainDiscovery: true,
|
||||||
|
DisableLoginWithEmail: true,
|
||||||
|
DisableLoginWithPhone: true,
|
||||||
|
DefaultRedirectURI: "example.com",
|
||||||
|
PasswordCheckLifetime: time.Hour,
|
||||||
|
ExternalLoginCheckLifetime: time.Minute,
|
||||||
|
MFAInitSkipLifetime: time.Millisecond,
|
||||||
|
SecondFactorCheckLifetime: time.Microsecond,
|
||||||
|
MultiFactorCheckLifetime: time.Nanosecond,
|
||||||
|
SecondFactors: []domain.SecondFactorType{
|
||||||
|
domain.SecondFactorTypeOTP,
|
||||||
|
domain.SecondFactorTypeU2F,
|
||||||
|
},
|
||||||
|
MultiFactors: []domain.MultiFactorType{
|
||||||
|
domain.MultiFactorTypeU2FWithPIN,
|
||||||
|
},
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
want := &settings.LoginSettings{
|
||||||
|
AllowUsernamePassword: true,
|
||||||
|
AllowRegister: true,
|
||||||
|
AllowExternalIdp: true,
|
||||||
|
ForceMfa: true,
|
||||||
|
PasskeysType: settings.PasskeysType_PASSKEYS_TYPE_ALLOWED,
|
||||||
|
HidePasswordReset: true,
|
||||||
|
IgnoreUnknownUsernames: true,
|
||||||
|
AllowDomainDiscovery: true,
|
||||||
|
DisableLoginWithEmail: true,
|
||||||
|
DisableLoginWithPhone: true,
|
||||||
|
DefaultRedirectUri: "example.com",
|
||||||
|
PasswordCheckLifetime: durationpb.New(time.Hour),
|
||||||
|
ExternalLoginCheckLifetime: durationpb.New(time.Minute),
|
||||||
|
MfaInitSkipLifetime: durationpb.New(time.Millisecond),
|
||||||
|
SecondFactorCheckLifetime: durationpb.New(time.Microsecond),
|
||||||
|
MultiFactorCheckLifetime: durationpb.New(time.Nanosecond),
|
||||||
|
SecondFactors: []settings.SecondFactorType{
|
||||||
|
settings.SecondFactorType_SECOND_FACTOR_TYPE_OTP,
|
||||||
|
settings.SecondFactorType_SECOND_FACTOR_TYPE_U2F,
|
||||||
|
},
|
||||||
|
MultiFactors: []settings.MultiFactorType{
|
||||||
|
settings.MultiFactorType_MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION,
|
||||||
|
},
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := loginSettingsToPb(arg)
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("loginSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_isDefaultToResourceOwnerTypePb(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
isDefault bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want settings.ResourceOwnerType
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{false},
|
||||||
|
want: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_ORG,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{true},
|
||||||
|
want: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.want.String(), func(t *testing.T) {
|
||||||
|
got := isDefaultToResourceOwnerTypePb(tt.args.isDefault)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_passkeysTypeToPb(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
passwordlessType domain.PasswordlessType
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want settings.PasskeysType
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{domain.PasswordlessTypeNotAllowed},
|
||||||
|
want: settings.PasskeysType_PASSKEYS_TYPE_NOT_ALLOWED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.PasswordlessTypeAllowed},
|
||||||
|
want: settings.PasskeysType_PASSKEYS_TYPE_ALLOWED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{99},
|
||||||
|
want: settings.PasskeysType_PASSKEYS_TYPE_NOT_ALLOWED,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.want.String(), func(t *testing.T) {
|
||||||
|
got := passkeysTypeToPb(tt.args.passwordlessType)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_secondFactorTypeToPb(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
secondFactorType domain.SecondFactorType
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want settings.SecondFactorType
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{domain.SecondFactorTypeOTP},
|
||||||
|
want: settings.SecondFactorType_SECOND_FACTOR_TYPE_OTP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.SecondFactorTypeU2F},
|
||||||
|
want: settings.SecondFactorType_SECOND_FACTOR_TYPE_U2F,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.SecondFactorTypeUnspecified},
|
||||||
|
want: settings.SecondFactorType_SECOND_FACTOR_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{99},
|
||||||
|
want: settings.SecondFactorType_SECOND_FACTOR_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.want.String(), func(t *testing.T) {
|
||||||
|
got := secondFactorTypeToPb(tt.args.secondFactorType)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_multiFactorTypeToPb(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
typ domain.MultiFactorType
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want settings.MultiFactorType
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{domain.MultiFactorTypeU2FWithPIN},
|
||||||
|
want: settings.MultiFactorType_MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.MultiFactorTypeUnspecified},
|
||||||
|
want: settings.MultiFactorType_MULTI_FACTOR_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{99},
|
||||||
|
want: settings.MultiFactorType_MULTI_FACTOR_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.want.String(), func(t *testing.T) {
|
||||||
|
got := multiFactorTypeToPb(tt.args.typ)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_passwordSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.PasswordComplexityPolicy{
|
||||||
|
MinLength: 12,
|
||||||
|
HasUppercase: true,
|
||||||
|
HasLowercase: true,
|
||||||
|
HasNumber: true,
|
||||||
|
HasSymbol: true,
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
want := &settings.PasswordComplexitySettings{
|
||||||
|
MinLength: 12,
|
||||||
|
RequiresUppercase: true,
|
||||||
|
RequiresLowercase: true,
|
||||||
|
RequiresNumber: true,
|
||||||
|
RequiresSymbol: true,
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := passwordSettingsToPb(arg)
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("passwordSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_brandingSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.LabelPolicy{
|
||||||
|
Light: query.Theme{
|
||||||
|
PrimaryColor: "red",
|
||||||
|
WarnColor: "white",
|
||||||
|
BackgroundColor: "blue",
|
||||||
|
FontColor: "orange",
|
||||||
|
LogoURL: "light-logo",
|
||||||
|
IconURL: "light-icon",
|
||||||
|
},
|
||||||
|
Dark: query.Theme{
|
||||||
|
PrimaryColor: "magenta",
|
||||||
|
WarnColor: "pink",
|
||||||
|
BackgroundColor: "black",
|
||||||
|
FontColor: "white",
|
||||||
|
LogoURL: "dark-logo",
|
||||||
|
IconURL: "dark-icon",
|
||||||
|
},
|
||||||
|
ResourceOwner: "me",
|
||||||
|
FontURL: "fonts",
|
||||||
|
WatermarkDisabled: true,
|
||||||
|
HideLoginNameSuffix: true,
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
want := &settings.BrandingSettings{
|
||||||
|
LightTheme: &settings.Theme{
|
||||||
|
PrimaryColor: "red",
|
||||||
|
WarnColor: "white",
|
||||||
|
BackgroundColor: "blue",
|
||||||
|
FontColor: "orange",
|
||||||
|
LogoUrl: "http://example.com/me/light-logo",
|
||||||
|
IconUrl: "http://example.com/me/light-icon",
|
||||||
|
},
|
||||||
|
DarkTheme: &settings.Theme{
|
||||||
|
PrimaryColor: "magenta",
|
||||||
|
WarnColor: "pink",
|
||||||
|
BackgroundColor: "black",
|
||||||
|
FontColor: "white",
|
||||||
|
LogoUrl: "http://example.com/me/dark-logo",
|
||||||
|
IconUrl: "http://example.com/me/dark-icon",
|
||||||
|
},
|
||||||
|
FontUrl: "http://example.com/me/fonts",
|
||||||
|
DisableWatermark: true,
|
||||||
|
HideLoginNameSuffix: true,
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
|
||||||
|
got := brandingSettingsToPb(arg, "http://example.com")
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("brandingSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_domainSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.DomainPolicy{
|
||||||
|
UserLoginMustBeDomain: true,
|
||||||
|
ValidateOrgDomains: true,
|
||||||
|
SMTPSenderAddressMatchesInstanceDomain: true,
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
want := &settings.DomainSettings{
|
||||||
|
LoginNameIncludesDomain: true,
|
||||||
|
RequireOrgDomainVerification: true,
|
||||||
|
SmtpSenderAddressMatchesInstanceDomain: true,
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
got := domainSettingsToPb(arg)
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("domainSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_legalSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.PrivacyPolicy{
|
||||||
|
TOSLink: "http://example.com/tos",
|
||||||
|
PrivacyLink: "http://example.com/pricacy",
|
||||||
|
HelpLink: "http://example.com/help",
|
||||||
|
SupportEmail: "support@zitadel.com",
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
want := &settings.LegalAndSupportSettings{
|
||||||
|
TosLink: "http://example.com/tos",
|
||||||
|
PrivacyPolicyLink: "http://example.com/pricacy",
|
||||||
|
HelpLink: "http://example.com/help",
|
||||||
|
SupportEmail: "support@zitadel.com",
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
got := legalAndSupportSettingsToPb(arg)
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("legalSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_lockoutSettingsToPb(t *testing.T) {
|
||||||
|
arg := &query.LockoutPolicy{
|
||||||
|
MaxPasswordAttempts: 22,
|
||||||
|
IsDefault: true,
|
||||||
|
}
|
||||||
|
want := &settings.LockoutSettings{
|
||||||
|
MaxPasswordAttempts: 22,
|
||||||
|
ResourceOwnerType: settings.ResourceOwnerType_RESOURCE_OWNER_TYPE_INSTANCE,
|
||||||
|
}
|
||||||
|
got := lockoutSettingsToPb(arg)
|
||||||
|
allFieldsSet(t, got.ProtoReflect())
|
||||||
|
if !proto.Equal(got, want) {
|
||||||
|
t.Errorf("lockoutSettingsToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_identityProvidersToPb(t *testing.T) {
|
||||||
|
arg := []*query.IDPLoginPolicyLink{
|
||||||
|
{
|
||||||
|
IDPID: "1",
|
||||||
|
IDPName: "foo",
|
||||||
|
IDPType: domain.IDPTypeOIDC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IDPID: "2",
|
||||||
|
IDPName: "bar",
|
||||||
|
IDPType: domain.IDPTypeGitHub,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
want := []*settings.IdentityProvider{
|
||||||
|
{
|
||||||
|
Id: "1",
|
||||||
|
Name: "foo",
|
||||||
|
Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OIDC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Id: "2",
|
||||||
|
Name: "bar",
|
||||||
|
Type: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := identityProvidersToPb(arg)
|
||||||
|
require.Len(t, got, len(got))
|
||||||
|
for i, v := range got {
|
||||||
|
allFieldsSet(t, v.ProtoReflect())
|
||||||
|
if !proto.Equal(v, want[i]) {
|
||||||
|
t.Errorf("identityProvidersToPb() =\n%v\nwant\n%v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_idpTypeToPb(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
idpType domain.IDPType
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want settings.IdentityProviderType
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeUnspecified},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeOIDC},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OIDC,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeJWT},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_JWT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeOAuth},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_OAUTH,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeLDAP},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_LDAP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeAzureAD},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_AZURE_AD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeGitHub},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeGitHubEnterprise},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITHUB_ES,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeGitLab},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITLAB,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeGitLabSelfHosted},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GITLAB_SELF_HOSTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{domain.IDPTypeGoogle},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_GOOGLE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{99},
|
||||||
|
want: settings.IdentityProviderType_IDENTITY_PROVIDER_TYPE_UNSPECIFIED,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.want.String(), func(t *testing.T) {
|
||||||
|
if got := idpTypeToPb(tt.args.idpType); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("idpTypeToPb() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import "github.com/zitadel/logging"
|
||||||
|
|
||||||
type IDPState int32
|
type IDPState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -56,3 +58,36 @@ func (t IDPType) GetCSSClass() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IDPName(name string, idpType IDPType) string {
|
||||||
|
if name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return idpType.DisplayName()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisplayName returns the name or a default
|
||||||
|
// to be used when always a name must be displayed (e.g. login)
|
||||||
|
func (t IDPType) DisplayName() string {
|
||||||
|
switch t {
|
||||||
|
case IDPTypeGitHub:
|
||||||
|
return "GitHub"
|
||||||
|
case IDPTypeGitLab:
|
||||||
|
return "GitLab"
|
||||||
|
case IDPTypeGoogle:
|
||||||
|
return "Google"
|
||||||
|
case IDPTypeUnspecified,
|
||||||
|
IDPTypeOIDC,
|
||||||
|
IDPTypeJWT,
|
||||||
|
IDPTypeOAuth,
|
||||||
|
IDPTypeLDAP,
|
||||||
|
IDPTypeAzureAD,
|
||||||
|
IDPTypeGitHubEnterprise,
|
||||||
|
IDPTypeGitLabSelfHosted:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
// we should never get here, so log it
|
||||||
|
logging.Errorf("name of provider (type %d) is empty", t)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -70,30 +68,7 @@ func (p IDPProvider) IsValid() bool {
|
|||||||
// DisplayName returns the name or a default
|
// DisplayName returns the name or a default
|
||||||
// to be used when always a name must be displayed (e.g. login)
|
// to be used when always a name must be displayed (e.g. login)
|
||||||
func (p IDPProvider) DisplayName() string {
|
func (p IDPProvider) DisplayName() string {
|
||||||
if p.Name != "" {
|
return IDPName(p.Name, p.IDPType)
|
||||||
return p.Name
|
|
||||||
}
|
|
||||||
switch p.IDPType {
|
|
||||||
case IDPTypeGitHub:
|
|
||||||
return "GitHub"
|
|
||||||
case IDPTypeGitLab:
|
|
||||||
return "GitLab"
|
|
||||||
case IDPTypeGoogle:
|
|
||||||
return "Google"
|
|
||||||
case IDPTypeUnspecified,
|
|
||||||
IDPTypeOIDC,
|
|
||||||
IDPTypeJWT,
|
|
||||||
IDPTypeOAuth,
|
|
||||||
IDPTypeLDAP,
|
|
||||||
IDPTypeAzureAD,
|
|
||||||
IDPTypeGitHubEnterprise,
|
|
||||||
IDPTypeGitLabSelfHosted:
|
|
||||||
fallthrough
|
|
||||||
default:
|
|
||||||
// we should never get here, so log it
|
|
||||||
logging.Errorf("name of provider (type %d) is empty - id: %s", p.IDPType, p.IDPConfigID)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PasswordlessType int32
|
type PasswordlessType int32
|
||||||
|
@ -80,27 +80,33 @@ var (
|
|||||||
name: projection.IDPLoginPolicyLinkOwnerRemovedCol,
|
name: projection.IDPLoginPolicyLinkOwnerRemovedCol,
|
||||||
table: idpLoginPolicyLinkTable,
|
table: idpLoginPolicyLinkTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
idpLoginPolicyOwnerTable = loginPolicyTable.setAlias("login_policy_owner")
|
||||||
|
idpLoginPolicyOwnerIDCol = LoginPolicyColumnOrgID.setTable(idpLoginPolicyOwnerTable)
|
||||||
|
idpLoginPolicyOwnerInstanceIDCol = LoginPolicyColumnInstanceID.setTable(idpLoginPolicyOwnerTable)
|
||||||
|
idpLoginPolicyOwnerIsDefaultCol = LoginPolicyColumnIsDefault.setTable(idpLoginPolicyOwnerTable)
|
||||||
|
idpLoginPolicyOwnerOwnerRemovedCol = LoginPolicyColumnOwnerRemoved.setTable(idpLoginPolicyOwnerTable)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, queries *IDPLoginPolicyLinksSearchQuery, withOwnerRemoved bool) (idps *IDPLoginPolicyLinks, err error) {
|
func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string, queries *IDPLoginPolicyLinksSearchQuery, withOwnerRemoved bool) (idps *IDPLoginPolicyLinks, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
query, scan := prepareIDPLoginPolicyLinksQuery(ctx, q.client)
|
query, scan := prepareIDPLoginPolicyLinksQuery(ctx, q.client, resourceOwner)
|
||||||
eq := sq.Eq{
|
eq := sq.Eq{
|
||||||
IDPLoginPolicyLinkResourceOwnerCol.identifier(): resourceOwner,
|
|
||||||
IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
IDPLoginPolicyLinkInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||||
}
|
}
|
||||||
if !withOwnerRemoved {
|
if !withOwnerRemoved {
|
||||||
eq[IDPLoginPolicyLinkOwnerRemovedCol.identifier()] = false
|
eq[IDPLoginPolicyLinkOwnerRemovedCol.identifier()] = false
|
||||||
|
eq[idpLoginPolicyOwnerOwnerRemovedCol.identifier()] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-FDbKW", "Errors.Query.InvalidRequest")
|
return nil, errors.ThrowInvalidArgument(err, "QUERY-FDbKW", "Errors.Query.InvalidRequest")
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||||
if err != nil {
|
if err != nil || rows.Err() != nil {
|
||||||
return nil, errors.ThrowInternal(err, "QUERY-ZkKUc", "Errors.Internal")
|
return nil, errors.ThrowInternal(err, "QUERY-ZkKUc", "Errors.Internal")
|
||||||
}
|
}
|
||||||
idps, err = scan(rows)
|
idps, err = scan(rows)
|
||||||
@ -111,7 +117,11 @@ func (q *Queries) IDPLoginPolicyLinks(ctx context.Context, resourceOwner string,
|
|||||||
return idps, err
|
return idps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase, resourceOwner string) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||||
|
resourceOwnerQuery, resourceOwnerArgs, err := prepareIDPLoginPolicyLinksResourceOwnerQuery(ctx, resourceOwner)
|
||||||
|
if err != nil {
|
||||||
|
return sq.SelectBuilder{}, nil
|
||||||
|
}
|
||||||
return sq.Select(
|
return sq.Select(
|
||||||
IDPLoginPolicyLinkIDPIDCol.identifier(),
|
IDPLoginPolicyLinkIDPIDCol.identifier(),
|
||||||
IDPTemplateNameCol.identifier(),
|
IDPTemplateNameCol.identifier(),
|
||||||
@ -119,7 +129,12 @@ func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase) (s
|
|||||||
IDPTemplateOwnerTypeCol.identifier(),
|
IDPTemplateOwnerTypeCol.identifier(),
|
||||||
countColumn.identifier()).
|
countColumn.identifier()).
|
||||||
From(idpLoginPolicyLinkTable.identifier()).
|
From(idpLoginPolicyLinkTable.identifier()).
|
||||||
LeftJoin(join(IDPTemplateIDCol, IDPLoginPolicyLinkIDPIDCol) + db.Timetravel(call.Took(ctx))).
|
LeftJoin(join(IDPTemplateIDCol, IDPLoginPolicyLinkIDPIDCol)).
|
||||||
|
RightJoin("("+resourceOwnerQuery+") AS "+idpLoginPolicyOwnerTable.alias+" ON "+
|
||||||
|
idpLoginPolicyOwnerIDCol.identifier()+" = "+IDPLoginPolicyLinkResourceOwnerCol.identifier()+" AND "+
|
||||||
|
idpLoginPolicyOwnerInstanceIDCol.identifier()+" = "+IDPLoginPolicyLinkInstanceIDCol.identifier()+
|
||||||
|
" "+db.Timetravel(call.Took(ctx)),
|
||||||
|
resourceOwnerArgs...).
|
||||||
PlaceholderFormat(sq.Dollar),
|
PlaceholderFormat(sq.Dollar),
|
||||||
func(rows *sql.Rows) (*IDPLoginPolicyLinks, error) {
|
func(rows *sql.Rows) (*IDPLoginPolicyLinks, error) {
|
||||||
links := make([]*IDPLoginPolicyLink, 0)
|
links := make([]*IDPLoginPolicyLink, 0)
|
||||||
@ -164,3 +179,22 @@ func prepareIDPLoginPolicyLinksQuery(ctx context.Context, db prepareDatabase) (s
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareIDPLoginPolicyLinksResourceOwnerQuery(ctx context.Context, resourceOwner string) (string, []interface{}, error) {
|
||||||
|
eqPolicy := sq.Eq{idpLoginPolicyOwnerInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID()}
|
||||||
|
return sq.Select(
|
||||||
|
idpLoginPolicyOwnerIDCol.identifier(),
|
||||||
|
idpLoginPolicyOwnerInstanceIDCol.identifier(),
|
||||||
|
idpLoginPolicyOwnerOwnerRemovedCol.identifier(),
|
||||||
|
).
|
||||||
|
From(idpLoginPolicyOwnerTable.identifier()).
|
||||||
|
Where(
|
||||||
|
sq.And{
|
||||||
|
eqPolicy,
|
||||||
|
sq.Or{
|
||||||
|
sq.Eq{idpLoginPolicyOwnerIDCol.identifier(): resourceOwner},
|
||||||
|
sq.Eq{idpLoginPolicyOwnerIDCol.identifier(): authz.GetInstance(ctx).InstanceID()},
|
||||||
|
},
|
||||||
|
}).
|
||||||
|
Limit(1).OrderBy(idpLoginPolicyOwnerIsDefaultCol.identifier()).ToSql()
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package query
|
package query
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"errors"
|
"errors"
|
||||||
@ -8,6 +9,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,6 +22,9 @@ var (
|
|||||||
` COUNT(*) OVER ()` +
|
` COUNT(*) OVER ()` +
|
||||||
` FROM projections.idp_login_policy_links5` +
|
` FROM projections.idp_login_policy_links5` +
|
||||||
` LEFT JOIN projections.idp_templates5 ON projections.idp_login_policy_links5.idp_id = projections.idp_templates5.id AND projections.idp_login_policy_links5.instance_id = projections.idp_templates5.instance_id` +
|
` LEFT JOIN projections.idp_templates5 ON projections.idp_login_policy_links5.idp_id = projections.idp_templates5.id AND projections.idp_login_policy_links5.instance_id = projections.idp_templates5.instance_id` +
|
||||||
|
` RIGHT JOIN (SELECT login_policy_owner.aggregate_id, login_policy_owner.instance_id, login_policy_owner.owner_removed FROM projections.login_policies4 AS login_policy_owner` +
|
||||||
|
` WHERE (login_policy_owner.instance_id = $1 AND (login_policy_owner.aggregate_id = $2 OR login_policy_owner.aggregate_id = $3)) ORDER BY login_policy_owner.is_default LIMIT 1) AS login_policy_owner` +
|
||||||
|
` ON login_policy_owner.aggregate_id = projections.idp_login_policy_links5.resource_owner AND login_policy_owner.instance_id = projections.idp_login_policy_links5.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
loginPolicyIDPLinksCols = []string{
|
loginPolicyIDPLinksCols = []string{
|
||||||
"idp_id",
|
"idp_id",
|
||||||
@ -42,7 +48,9 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "prepareIDPsQuery found",
|
name: "prepareIDPsQuery found",
|
||||||
prepare: prepareIDPLoginPolicyLinksQuery,
|
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||||
|
return prepareIDPLoginPolicyLinksQuery(ctx, db, "resourceOwner")
|
||||||
|
},
|
||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
loginPolicyIDPLinksQuery,
|
loginPolicyIDPLinksQuery,
|
||||||
@ -73,7 +81,9 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareIDPsQuery no idp",
|
name: "prepareIDPsQuery no idp",
|
||||||
prepare: prepareIDPLoginPolicyLinksQuery,
|
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||||
|
return prepareIDPLoginPolicyLinksQuery(ctx, db, "resourceOwner")
|
||||||
|
},
|
||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
loginPolicyIDPLinksQuery,
|
loginPolicyIDPLinksQuery,
|
||||||
@ -103,7 +113,9 @@ func Test_IDPLoginPolicyLinkPrepares(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prepareIDPsQuery sql err",
|
name: "prepareIDPsQuery sql err",
|
||||||
prepare: prepareIDPLoginPolicyLinksQuery,
|
prepare: func(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*IDPLoginPolicyLinks, error)) {
|
||||||
|
return prepareIDPLoginPolicyLinksQuery(ctx, db, "resourceOwner")
|
||||||
|
},
|
||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQueryErr(
|
sqlExpectations: mockQueryErr(
|
||||||
loginPolicyIDPLinksQuery,
|
loginPolicyIDPLinksQuery,
|
||||||
|
@ -15,6 +15,13 @@ message Organisation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message RequestContext {
|
||||||
|
oneof resource_owner {
|
||||||
|
string org_id = 1;
|
||||||
|
bool instance = 2 [(validate.rules).bool = {const: true}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message ListQuery {
|
message ListQuery {
|
||||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
||||||
json_schema: {
|
json_schema: {
|
||||||
|
81
proto/zitadel/settings/v2alpha/branding_settings.proto
Normal file
81
proto/zitadel/settings/v2alpha/branding_settings.proto
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
|
||||||
|
message BrandingSettings {
|
||||||
|
Theme light_theme = 1;
|
||||||
|
Theme dark_theme = 2;
|
||||||
|
string font_url = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "url to the font used";
|
||||||
|
example: "\"https://acme.com/assets/v1/165617850692654601/policy/label/font-180950243237405441\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// hides the org suffix on the login form if the scope \"urn:zitadel:iam:org:domain:primary:{domainname}\" is set
|
||||||
|
bool hide_login_name_suffix = 4 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "hides the org suffix on the login form if the scope \"urn:zitadel:iam:org:domain:primary:{domainname}\" is set";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool disable_watermark = 5 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "boolean to disable the watermark";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the setting is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the setting is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Theme {
|
||||||
|
// hex value for primary color
|
||||||
|
string primary_color = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "hex value for primary color";
|
||||||
|
example: "\"#5469d4\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// hex value for background color
|
||||||
|
string background_color = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "hex value for background color";
|
||||||
|
example: "\"#FAFAFA\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// hex value for warning color
|
||||||
|
string warn_color = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "hex value for warn color";
|
||||||
|
example: "\"#CD3D56\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// hex value for font color
|
||||||
|
string font_color = 4 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "hex value for font color";
|
||||||
|
example: "\"#000000\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// url where the logo is served
|
||||||
|
string logo_url = 5 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "url to the logo";
|
||||||
|
example: "\"https://acme.com/assets/v1/165617850692654601/policy/label/logo-180950416321494657\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// url where the icon is served
|
||||||
|
string icon_url = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "url to the icon";
|
||||||
|
example: "\"https://acme.com/assets/v1/165617850692654601/policy/label/icon-180950498874178817\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
33
proto/zitadel/settings/v2alpha/domain_settings.proto
Normal file
33
proto/zitadel/settings/v2alpha/domain_settings.proto
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
|
||||||
|
message DomainSettings {
|
||||||
|
bool login_name_includes_domain = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "the username has to end with the domain of its organization"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool require_org_domain_verification = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if organization domains should be verified upon creation, otherwise will be created already verified"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool smtp_sender_address_matches_instance_domain = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the SMTP sender address domain should match an existing domain on the instance"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the setting is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the setting is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
40
proto/zitadel/settings/v2alpha/legal_settings.proto
Normal file
40
proto/zitadel/settings/v2alpha/legal_settings.proto
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
import "validate/validate.proto";
|
||||||
|
|
||||||
|
message LegalAndSupportSettings {
|
||||||
|
string tos_link = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"https://zitadel.com/docs/legal/terms-of-service\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
string privacy_policy_link = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"https://zitadel.com/docs/legal/privacy-policy\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
string help_link = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"https://zitadel.com/docs/manuals/introduction\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
string support_email = 4 [
|
||||||
|
(validate.rules).string = {ignore_empty: true, max_len: 320, email: true},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"support-email@test.com\"";
|
||||||
|
description: "help / support email address."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the setting is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 5 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the setting is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
23
proto/zitadel/settings/v2alpha/lockout_settings.proto
Normal file
23
proto/zitadel/settings/v2alpha/lockout_settings.proto
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
|
||||||
|
message LockoutSettings {
|
||||||
|
uint64 max_password_attempts = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Maximum password check attempts before the account gets locked. Attempts are reset as soon as the password is entered correctly or the password is reset. If set to 0 the account will never be locked."
|
||||||
|
example: "\"10\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the settings is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the settings is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
143
proto/zitadel/settings/v2alpha/login_settings.proto
Normal file
143
proto/zitadel/settings/v2alpha/login_settings.proto
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
|
|
||||||
|
message LoginSettings {
|
||||||
|
bool allow_username_password = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if a user is allowed to log in with his username and password";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool allow_register = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if a person is allowed to register a user on this organization";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool allow_external_idp = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if a user is allowed to add a defined identity provider. E.g. Google auth";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool force_mfa = 4 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if a user MUST use a multi-factor to log in";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
PasskeysType passkeys_type = 5 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if passkeys are allowed for users"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool hide_password_reset = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if password reset link should be shown in the login screen"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool ignore_unknown_usernames = 7 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if unknown username on login screen directly returns an error or always displays the password screen"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
string default_redirect_uri = 8 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines where the user will be redirected to if the login is started without app context (e.g. from mail)";
|
||||||
|
example: "\"https://acme.com/ui/console\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Duration password_check_lifetime = 9 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines after how much time the user has to re-authenticate with the password.";
|
||||||
|
example: "\"864000s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Duration external_login_check_lifetime = 10 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines after how much time the user has to re-authenticate with an external provider.";
|
||||||
|
example: "\"864000s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Duration mfa_init_skip_lifetime = 11 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines after how much time the mfa prompt will be shown again.";
|
||||||
|
example: "\"2592000s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Duration second_factor_check_lifetime = 12 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines after how long the second-factor check is valid.";
|
||||||
|
example: "\"64800s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
google.protobuf.Duration multi_factor_check_lifetime = 13 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines how long the multi-factor check is valid.";
|
||||||
|
example: "\"43200s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
repeated SecondFactorType second_factors = 14;
|
||||||
|
repeated MultiFactorType multi_factors = 15;
|
||||||
|
// If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organization on success.
|
||||||
|
bool allow_domain_discovery = 16 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "If set to true, the suffix (@domain.com) of an unknown username input on the login screen will be matched against the org domains and will redirect to the registration of that organization on success."
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool disable_login_with_email = 17 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the user can additionally (to the login name) be identified by their verified email address"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool disable_login_with_phone = 18 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the user can additionally (to the login name) be identified by their verified phone number"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the settings is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 19 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the settings is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SecondFactorType {
|
||||||
|
SECOND_FACTOR_TYPE_UNSPECIFIED = 0;
|
||||||
|
SECOND_FACTOR_TYPE_OTP = 1;
|
||||||
|
SECOND_FACTOR_TYPE_U2F = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MultiFactorType {
|
||||||
|
MULTI_FACTOR_TYPE_UNSPECIFIED = 0;
|
||||||
|
MULTI_FACTOR_TYPE_U2F_WITH_VERIFICATION = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PasskeysType {
|
||||||
|
PASSKEYS_TYPE_NOT_ALLOWED = 0;
|
||||||
|
PASSKEYS_TYPE_ALLOWED = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message IdentityProvider {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
IdentityProviderType type = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum IdentityProviderType {
|
||||||
|
IDENTITY_PROVIDER_TYPE_UNSPECIFIED = 0;
|
||||||
|
IDENTITY_PROVIDER_TYPE_OIDC = 1;
|
||||||
|
IDENTITY_PROVIDER_TYPE_JWT = 2;
|
||||||
|
IDENTITY_PROVIDER_TYPE_LDAP = 3;
|
||||||
|
IDENTITY_PROVIDER_TYPE_OAUTH = 4;
|
||||||
|
IDENTITY_PROVIDER_TYPE_AZURE_AD = 5;
|
||||||
|
IDENTITY_PROVIDER_TYPE_GITHUB = 6;
|
||||||
|
IDENTITY_PROVIDER_TYPE_GITHUB_ES = 7;
|
||||||
|
IDENTITY_PROVIDER_TYPE_GITLAB = 8;
|
||||||
|
IDENTITY_PROVIDER_TYPE_GITLAB_SELF_HOSTED = 9;
|
||||||
|
IDENTITY_PROVIDER_TYPE_GOOGLE = 10;
|
||||||
|
}
|
43
proto/zitadel/settings/v2alpha/password_settings.proto
Normal file
43
proto/zitadel/settings/v2alpha/password_settings.proto
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "zitadel/settings/v2alpha/settings.proto";
|
||||||
|
|
||||||
|
message PasswordComplexitySettings {
|
||||||
|
uint64 min_length = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "Defines the minimum length of a password.";
|
||||||
|
example: "\"8\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool requires_uppercase = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the password MUST contain an upper case letter"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool requires_lowercase = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the password MUST contain a lowercase letter"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool requires_number = 4 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the password MUST contain a number"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
bool requires_symbol = 5 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines if the password MUST contain a symbol. E.g. \"$\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// resource_owner_type returns if the settings is managed on the organization or on the instance
|
||||||
|
ResourceOwnerType resource_owner_type = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "resource_owner_type returns if the settings is managed on the organization or on the instance";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
13
proto/zitadel/settings/v2alpha/settings.proto
Normal file
13
proto/zitadel/settings/v2alpha/settings.proto
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
|
||||||
|
enum ResourceOwnerType {
|
||||||
|
RESOURCE_OWNER_TYPE_UNSPECIFIED = 0;
|
||||||
|
RESOURCE_OWNER_TYPE_INSTANCE = 1;
|
||||||
|
RESOURCE_OWNER_TYPE_ORG = 2;
|
||||||
|
}
|
356
proto/zitadel/settings/v2alpha/settings_service.proto
Normal file
356
proto/zitadel/settings/v2alpha/settings_service.proto
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.settings.v2alpha;
|
||||||
|
|
||||||
|
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
||||||
|
import "zitadel/object/v2alpha/object.proto";
|
||||||
|
import "zitadel/settings/v2alpha/branding_settings.proto";
|
||||||
|
import "zitadel/settings/v2alpha/domain_settings.proto";
|
||||||
|
import "zitadel/settings/v2alpha/legal_settings.proto";
|
||||||
|
import "zitadel/settings/v2alpha/lockout_settings.proto";
|
||||||
|
import "zitadel/settings/v2alpha/login_settings.proto";
|
||||||
|
import "zitadel/settings/v2alpha/password_settings.proto";
|
||||||
|
import "google/api/annotations.proto";
|
||||||
|
import "google/api/field_behavior.proto";
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "validate/validate.proto";
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/settings/v2alpha;settings";
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||||
|
info: {
|
||||||
|
title: "Settings Service";
|
||||||
|
version: "2.0-alpha";
|
||||||
|
description: "This API is intended to manage settings in a ZITADEL instance. This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.";
|
||||||
|
contact:{
|
||||||
|
name: "ZITADEL"
|
||||||
|
url: "https://zitadel.com"
|
||||||
|
email: "hi@zitadel.com"
|
||||||
|
}
|
||||||
|
license: {
|
||||||
|
name: "Apache 2.0",
|
||||||
|
url: "https://github.com/zitadel/zitadel/blob/main/LICENSE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
schemes: HTTPS;
|
||||||
|
schemes: HTTP;
|
||||||
|
|
||||||
|
consumes: "application/json";
|
||||||
|
consumes: "application/grpc";
|
||||||
|
|
||||||
|
produces: "application/json";
|
||||||
|
produces: "application/grpc";
|
||||||
|
|
||||||
|
consumes: "application/grpc-web+proto";
|
||||||
|
produces: "application/grpc-web+proto";
|
||||||
|
|
||||||
|
host: "$ZITADEL_DOMAIN";
|
||||||
|
base_path: "/";
|
||||||
|
|
||||||
|
external_docs: {
|
||||||
|
description: "Detailed information about ZITADEL",
|
||||||
|
url: "https://zitadel.com/docs"
|
||||||
|
}
|
||||||
|
|
||||||
|
responses: {
|
||||||
|
key: "403";
|
||||||
|
value: {
|
||||||
|
description: "Returned when the user does not have permission to access the resource.";
|
||||||
|
schema: {
|
||||||
|
json_schema: {
|
||||||
|
ref: "#/definitions/rpcStatus";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responses: {
|
||||||
|
key: "404";
|
||||||
|
value: {
|
||||||
|
description: "Returned when the resource does not exist.";
|
||||||
|
schema: {
|
||||||
|
json_schema: {
|
||||||
|
ref: "#/definitions/rpcStatus";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
service SettingsService {
|
||||||
|
|
||||||
|
// Get basic information over the instance
|
||||||
|
rpc GetGeneralSettings (GetGeneralSettingsRequest) returns (GetGeneralSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get basic information over the instance";
|
||||||
|
description: "Return the basic information of the instance for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the login settings
|
||||||
|
rpc GetLoginSettings (GetLoginSettingsRequest) returns (GetLoginSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/login"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the login settings";
|
||||||
|
description: "Return the settings for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current active identity providers
|
||||||
|
rpc GetActiveIdentityProviders (GetActiveIdentityProvidersRequest) returns (GetActiveIdentityProvidersResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/login/idps"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the current active identity providers";
|
||||||
|
description: "Return the current active identity providers for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the password complexity settings
|
||||||
|
rpc GetPasswordComplexitySettings (GetPasswordComplexitySettingsRequest) returns (GetPasswordComplexitySettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/password/complexity"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the password complexity settings";
|
||||||
|
description: "Return the password complexity settings for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current active branding settings
|
||||||
|
rpc GetBrandingSettings (GetBrandingSettingsRequest) returns (GetBrandingSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/branding"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the current active branding settings";
|
||||||
|
description: "Return the current active branding settings for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the domain settings
|
||||||
|
rpc GetDomainSettings (GetDomainSettingsRequest) returns (GetDomainSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/domain"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the domain settings";
|
||||||
|
description: "Return the domain settings for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the legal and support settings
|
||||||
|
rpc GetLegalAndSupportSettings (GetLegalAndSupportSettingsRequest) returns (GetLegalAndSupportSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/legal_support"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the legal and support settings";
|
||||||
|
description: "Return the legal settings for the requested context"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lockout settings
|
||||||
|
rpc GetLockoutSettings (GetLockoutSettingsRequest) returns (GetLockoutSettingsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2alpha/settings/lockout"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "policy.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
summary: "Get the lockout settings";
|
||||||
|
description: "Return the lockout settings for the requested context, which define when a user will be locked"
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "OK";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLoginSettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLoginSettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.LoginSettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPasswordComplexitySettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPasswordComplexitySettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.PasswordComplexitySettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetBrandingSettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetBrandingSettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.BrandingSettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetDomainSettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetDomainSettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.DomainSettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLegalAndSupportSettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLegalAndSupportSettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.LegalAndSupportSettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLockoutSettingsRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetLockoutSettingsResponse {
|
||||||
|
zitadel.object.v2alpha.Details details = 1;
|
||||||
|
zitadel.settings.v2alpha.LockoutSettings settings = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetActiveIdentityProvidersRequest {
|
||||||
|
zitadel.object.v2alpha.RequestContext ctx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetActiveIdentityProvidersResponse {
|
||||||
|
zitadel.object.v2alpha.ListDetails details = 1;
|
||||||
|
repeated zitadel.settings.v2alpha.IdentityProvider identity_providers = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetGeneralSettingsRequest {}
|
||||||
|
|
||||||
|
message GetGeneralSettingsResponse {
|
||||||
|
string default_org_id = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "default organization for the current context"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
string default_language = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "default language for the current context"
|
||||||
|
example: "\"en\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
repeated string supported_languages = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "[\"en\", \"de\", \"it\"]"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user