mirror of
https://github.com/zitadel/zitadel
synced 2024-11-21 16:30:53 +00:00
feat: idp v2 api GetIDPByID (#8425)
# Which Problems Are Solved GetIDPByID as endpoint in the API v2 so that it can be available for the new login. # How the Problems Are Solved Create GetIDPByID endpoint with IDP v2 API, throught the GetProviderByID implementation from admin and management API. # Additional Changes - Remove the OwnerType attribute from the response, as the information is available through the resourceOwner. - correct refs to messages in proto which are used for doc generation - renaming of elements for API v3 # Additional Context Closes #8337 --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
parent
64a3bb3149
commit
3e3d46ac0d
@ -38,6 +38,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/auth"
|
||||
feature_v2 "github.com/zitadel/zitadel/internal/api/grpc/feature/v2"
|
||||
feature_v2beta "github.com/zitadel/zitadel/internal/api/grpc/feature/v2beta"
|
||||
idp_v2 "github.com/zitadel/zitadel/internal/api/grpc/idp/v2"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/management"
|
||||
oidc_v2 "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2"
|
||||
oidc_v2beta "github.com/zitadel/zitadel/internal/api/grpc/oidc/v2beta"
|
||||
@ -437,6 +438,9 @@ func startAPIs(
|
||||
if err := apis.RegisterService(ctx, feature_v2.CreateServer(commands, queries)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, idp_v2.CreateServer(commands, queries, permissionCheck)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := apis.RegisterService(ctx, action_v3_alpha.CreateServer(config.SystemDefaults, commands, queries, domain.AllFunctions, apis.ListGrpcMethods, apis.ListGrpcServices)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -356,6 +356,14 @@ module.exports = {
|
||||
categoryLinkSource: "auto",
|
||||
},
|
||||
},
|
||||
idp_v2: {
|
||||
specPath: ".artifacts/openapi/zitadel/idp/v2/idp_service.swagger.json",
|
||||
outputDir: "docs/apis/resources/idp_service_v2",
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
categoryLinkSource: "auto",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -673,12 +673,24 @@ module.exports = {
|
||||
link: {
|
||||
type: "generated-index",
|
||||
title: "Feature Service API",
|
||||
slug: "/apis/resources/feature_service/v2",
|
||||
slug: "/apis/resources/feature_service_v2",
|
||||
description:
|
||||
'This API is intended to manage features for ZITADEL. Feature settings that are available on multiple "levels", such as instance and organization. The higher level instance acts as a default for the lower level. When a feature is set on multiple levels, the lower level takes precedence. Features can be experimental where ZITADEL will assume a sane default, such as disabled. When over time confidence in such a feature grows, ZITADEL can default to enabling the feature. As a final step we might choose to always enable a feature and remove the setting from this API, reserving the proto field number. Such removal is not considered a breaking change. Setting a removed field will effectively result in a no-op.\n'
|
||||
},
|
||||
items: require("./docs/apis/resources/feature_service_v2/sidebar.ts"),
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Identity Provider Lifecycle",
|
||||
link: {
|
||||
type: "generated-index",
|
||||
title: "Identity Provider Service API",
|
||||
slug: "/apis/resources/idp_service_v2",
|
||||
description:
|
||||
'This API is intended to manage identity providers (IdPs) for ZITADEL.\n'
|
||||
},
|
||||
items: require("./docs/apis/resources/idp_service_v2/sidebar.ts"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -157,7 +157,7 @@ func (s *Server) GetProviderByID(ctx context.Context, req *admin_pb.GetProviderB
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, instanceIDQuery)
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, nil, instanceIDQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
369
internal/api/grpc/idp/v2/query.go
Normal file
369
internal/api/grpc/idp/v2/query.go
Normal file
@ -0,0 +1,369 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/crewjam/saml"
|
||||
"github.com/muhlemmer/gu"
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/azuread"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
idp_rp "github.com/zitadel/zitadel/internal/repository/idp"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
|
||||
)
|
||||
|
||||
func (s *Server) GetIDPByID(ctx context.Context, req *idp_pb.GetIDPByIDRequest) (*idp_pb.GetIDPByIDResponse, error) {
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, s.checkPermission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &idp_pb.GetIDPByIDResponse{Idp: idpToPb(idp)}, nil
|
||||
}
|
||||
|
||||
func idpToPb(idp *query.IDPTemplate) *idp_pb.IDP {
|
||||
return &idp_pb.IDP{
|
||||
Id: idp.ID,
|
||||
Details: object.DomainToDetailsPb(
|
||||
&domain.ObjectDetails{
|
||||
Sequence: idp.Sequence,
|
||||
EventDate: idp.ChangeDate,
|
||||
ResourceOwner: idp.ResourceOwner,
|
||||
}),
|
||||
State: idpStateToPb(idp.State),
|
||||
Name: idp.Name,
|
||||
Type: idpTypeToPb(idp.Type),
|
||||
Config: configToPb(idp),
|
||||
}
|
||||
}
|
||||
|
||||
func idpStateToPb(state domain.IDPState) idp_pb.IDPState {
|
||||
switch state {
|
||||
case domain.IDPStateActive:
|
||||
return idp_pb.IDPState_IDP_STATE_ACTIVE
|
||||
case domain.IDPStateInactive:
|
||||
return idp_pb.IDPState_IDP_STATE_INACTIVE
|
||||
case domain.IDPStateUnspecified:
|
||||
return idp_pb.IDPState_IDP_STATE_UNSPECIFIED
|
||||
case domain.IDPStateMigrated:
|
||||
return idp_pb.IDPState_IDP_STATE_MIGRATED
|
||||
case domain.IDPStateRemoved:
|
||||
return idp_pb.IDPState_IDP_STATE_REMOVED
|
||||
default:
|
||||
return idp_pb.IDPState_IDP_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func idpTypeToPb(idpType domain.IDPType) idp_pb.IDPType {
|
||||
switch idpType {
|
||||
case domain.IDPTypeOIDC:
|
||||
return idp_pb.IDPType_IDP_TYPE_OIDC
|
||||
case domain.IDPTypeJWT:
|
||||
return idp_pb.IDPType_IDP_TYPE_JWT
|
||||
case domain.IDPTypeOAuth:
|
||||
return idp_pb.IDPType_IDP_TYPE_OAUTH
|
||||
case domain.IDPTypeLDAP:
|
||||
return idp_pb.IDPType_IDP_TYPE_LDAP
|
||||
case domain.IDPTypeAzureAD:
|
||||
return idp_pb.IDPType_IDP_TYPE_AZURE_AD
|
||||
case domain.IDPTypeGitHub:
|
||||
return idp_pb.IDPType_IDP_TYPE_GITHUB
|
||||
case domain.IDPTypeGitHubEnterprise:
|
||||
return idp_pb.IDPType_IDP_TYPE_GITHUB_ES
|
||||
case domain.IDPTypeGitLab:
|
||||
return idp_pb.IDPType_IDP_TYPE_GITLAB
|
||||
case domain.IDPTypeGitLabSelfHosted:
|
||||
return idp_pb.IDPType_IDP_TYPE_GITLAB_SELF_HOSTED
|
||||
case domain.IDPTypeGoogle:
|
||||
return idp_pb.IDPType_IDP_TYPE_GOOGLE
|
||||
case domain.IDPTypeApple:
|
||||
return idp_pb.IDPType_IDP_TYPE_APPLE
|
||||
case domain.IDPTypeSAML:
|
||||
return idp_pb.IDPType_IDP_TYPE_SAML
|
||||
case domain.IDPTypeUnspecified:
|
||||
return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED
|
||||
default:
|
||||
return idp_pb.IDPType_IDP_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func configToPb(config *query.IDPTemplate) *idp_pb.IDPConfig {
|
||||
idpConfig := &idp_pb.IDPConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsLinkingAllowed: config.IsLinkingAllowed,
|
||||
IsCreationAllowed: config.IsCreationAllowed,
|
||||
IsAutoCreation: config.IsAutoCreation,
|
||||
IsAutoUpdate: config.IsAutoUpdate,
|
||||
AutoLinking: autoLinkingOptionToPb(config.AutoLinking),
|
||||
},
|
||||
}
|
||||
if config.OAuthIDPTemplate != nil {
|
||||
oauthConfigToPb(idpConfig, config.OAuthIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.OIDCIDPTemplate != nil {
|
||||
oidcConfigToPb(idpConfig, config.OIDCIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.JWTIDPTemplate != nil {
|
||||
jwtConfigToPb(idpConfig, config.JWTIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.AzureADIDPTemplate != nil {
|
||||
azureConfigToPb(idpConfig, config.AzureADIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.GitHubIDPTemplate != nil {
|
||||
githubConfigToPb(idpConfig, config.GitHubIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.GitHubEnterpriseIDPTemplate != nil {
|
||||
githubEnterpriseConfigToPb(idpConfig, config.GitHubEnterpriseIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.GitLabIDPTemplate != nil {
|
||||
gitlabConfigToPb(idpConfig, config.GitLabIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.GitLabSelfHostedIDPTemplate != nil {
|
||||
gitlabSelfHostedConfigToPb(idpConfig, config.GitLabSelfHostedIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.GoogleIDPTemplate != nil {
|
||||
googleConfigToPb(idpConfig, config.GoogleIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.LDAPIDPTemplate != nil {
|
||||
ldapConfigToPb(idpConfig, config.LDAPIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.AppleIDPTemplate != nil {
|
||||
appleConfigToPb(idpConfig, config.AppleIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
if config.SAMLIDPTemplate != nil {
|
||||
samlConfigToPb(idpConfig, config.SAMLIDPTemplate)
|
||||
return idpConfig
|
||||
}
|
||||
return idpConfig
|
||||
}
|
||||
|
||||
func autoLinkingOptionToPb(linking domain.AutoLinkingOption) idp_pb.AutoLinkingOption {
|
||||
switch linking {
|
||||
case domain.AutoLinkingOptionUnspecified:
|
||||
return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED
|
||||
case domain.AutoLinkingOptionUsername:
|
||||
return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME
|
||||
case domain.AutoLinkingOptionEmail:
|
||||
return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_EMAIL
|
||||
default:
|
||||
return idp_pb.AutoLinkingOption_AUTO_LINKING_OPTION_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func oauthConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.OAuthIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Oauth{
|
||||
Oauth: &idp_pb.OAuthConfig{
|
||||
ClientId: template.ClientID,
|
||||
AuthorizationEndpoint: template.AuthorizationEndpoint,
|
||||
TokenEndpoint: template.TokenEndpoint,
|
||||
UserEndpoint: template.UserEndpoint,
|
||||
Scopes: template.Scopes,
|
||||
IdAttribute: template.IDAttribute,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func oidcConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.OIDCIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Oidc{
|
||||
Oidc: &idp_pb.GenericOIDCConfig{
|
||||
ClientId: template.ClientID,
|
||||
Issuer: template.Issuer,
|
||||
Scopes: template.Scopes,
|
||||
IsIdTokenMapping: template.IsIDTokenMapping,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func jwtConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.JWTIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Jwt{
|
||||
Jwt: &idp_pb.JWTConfig{
|
||||
JwtEndpoint: template.Endpoint,
|
||||
Issuer: template.Issuer,
|
||||
KeysEndpoint: template.KeysEndpoint,
|
||||
HeaderName: template.HeaderName,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func azureConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.AzureADIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_AzureAd{
|
||||
AzureAd: &idp_pb.AzureADConfig{
|
||||
ClientId: template.ClientID,
|
||||
Tenant: azureTenantToPb(template.Tenant),
|
||||
EmailVerified: template.IsEmailVerified,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func azureTenantToPb(tenant string) *idp_pb.AzureADTenant {
|
||||
var tenantType idp_pb.IsAzureADTenantType
|
||||
switch azuread.TenantType(tenant) {
|
||||
case azuread.CommonTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_COMMON}
|
||||
case azuread.OrganizationsTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_ORGANISATIONS}
|
||||
case azuread.ConsumersTenant:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantType{TenantType: idp_pb.AzureADTenantType_AZURE_AD_TENANT_TYPE_CONSUMERS}
|
||||
default:
|
||||
tenantType = &idp_pb.AzureADTenant_TenantId{TenantId: tenant}
|
||||
}
|
||||
return &idp_pb.AzureADTenant{Type: tenantType}
|
||||
}
|
||||
|
||||
func githubConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.GitHubIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Github{
|
||||
Github: &idp_pb.GitHubConfig{
|
||||
ClientId: template.ClientID,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func githubEnterpriseConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.GitHubEnterpriseIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_GithubEs{
|
||||
GithubEs: &idp_pb.GitHubEnterpriseServerConfig{
|
||||
ClientId: template.ClientID,
|
||||
AuthorizationEndpoint: template.AuthorizationEndpoint,
|
||||
TokenEndpoint: template.TokenEndpoint,
|
||||
UserEndpoint: template.UserEndpoint,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func gitlabConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.GitLabIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Gitlab{
|
||||
Gitlab: &idp_pb.GitLabConfig{
|
||||
ClientId: template.ClientID,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func gitlabSelfHostedConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.GitLabSelfHostedIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_GitlabSelfHosted{
|
||||
GitlabSelfHosted: &idp_pb.GitLabSelfHostedConfig{
|
||||
ClientId: template.ClientID,
|
||||
Issuer: template.Issuer,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func googleConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.GoogleIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Google{
|
||||
Google: &idp_pb.GoogleConfig{
|
||||
ClientId: template.ClientID,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ldapConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.LDAPIDPTemplate) {
|
||||
var timeout *durationpb.Duration
|
||||
if template.Timeout != 0 {
|
||||
timeout = durationpb.New(template.Timeout)
|
||||
}
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Ldap{
|
||||
Ldap: &idp_pb.LDAPConfig{
|
||||
Servers: template.Servers,
|
||||
StartTls: template.StartTLS,
|
||||
BaseDn: template.BaseDN,
|
||||
BindDn: template.BindDN,
|
||||
UserBase: template.UserBase,
|
||||
UserObjectClasses: template.UserObjectClasses,
|
||||
UserFilters: template.UserFilters,
|
||||
Timeout: timeout,
|
||||
Attributes: ldapAttributesToPb(template.LDAPAttributes),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ldapAttributesToPb(attributes idp_rp.LDAPAttributes) *idp_pb.LDAPAttributes {
|
||||
return &idp_pb.LDAPAttributes{
|
||||
IdAttribute: attributes.IDAttribute,
|
||||
FirstNameAttribute: attributes.FirstNameAttribute,
|
||||
LastNameAttribute: attributes.LastNameAttribute,
|
||||
DisplayNameAttribute: attributes.DisplayNameAttribute,
|
||||
NickNameAttribute: attributes.NickNameAttribute,
|
||||
PreferredUsernameAttribute: attributes.PreferredUsernameAttribute,
|
||||
EmailAttribute: attributes.EmailAttribute,
|
||||
EmailVerifiedAttribute: attributes.EmailVerifiedAttribute,
|
||||
PhoneAttribute: attributes.PhoneAttribute,
|
||||
PhoneVerifiedAttribute: attributes.PhoneVerifiedAttribute,
|
||||
PreferredLanguageAttribute: attributes.PreferredLanguageAttribute,
|
||||
AvatarUrlAttribute: attributes.AvatarURLAttribute,
|
||||
ProfileAttribute: attributes.ProfileAttribute,
|
||||
}
|
||||
}
|
||||
|
||||
func appleConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.AppleIDPTemplate) {
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Apple{
|
||||
Apple: &idp_pb.AppleConfig{
|
||||
ClientId: template.ClientID,
|
||||
TeamId: template.TeamID,
|
||||
KeyId: template.KeyID,
|
||||
Scopes: template.Scopes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func samlConfigToPb(idpConfig *idp_pb.IDPConfig, template *query.SAMLIDPTemplate) {
|
||||
nameIDFormat := idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_PERSISTENT
|
||||
if template.NameIDFormat.Valid {
|
||||
nameIDFormat = nameIDToPb(template.NameIDFormat.V)
|
||||
}
|
||||
idpConfig.Config = &idp_pb.IDPConfig_Saml{
|
||||
Saml: &idp_pb.SAMLConfig{
|
||||
MetadataXml: template.Metadata,
|
||||
Binding: bindingToPb(template.Binding),
|
||||
WithSignedRequest: template.WithSignedRequest,
|
||||
NameIdFormat: nameIDFormat,
|
||||
TransientMappingAttributeName: gu.Ptr(template.TransientMappingAttributeName),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func bindingToPb(binding string) idp_pb.SAMLBinding {
|
||||
switch binding {
|
||||
case "":
|
||||
return idp_pb.SAMLBinding_SAML_BINDING_UNSPECIFIED
|
||||
case saml.HTTPPostBinding:
|
||||
return idp_pb.SAMLBinding_SAML_BINDING_POST
|
||||
case saml.HTTPRedirectBinding:
|
||||
return idp_pb.SAMLBinding_SAML_BINDING_REDIRECT
|
||||
case saml.HTTPArtifactBinding:
|
||||
return idp_pb.SAMLBinding_SAML_BINDING_ARTIFACT
|
||||
default:
|
||||
return idp_pb.SAMLBinding_SAML_BINDING_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func nameIDToPb(format domain.SAMLNameIDFormat) idp_pb.SAMLNameIDFormat {
|
||||
switch format {
|
||||
case domain.SAMLNameIDFormatUnspecified:
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
case domain.SAMLNameIDFormatEmailAddress:
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_EMAIL_ADDRESS
|
||||
case domain.SAMLNameIDFormatPersistent:
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_PERSISTENT
|
||||
case domain.SAMLNameIDFormatTransient:
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_TRANSIENT
|
||||
default:
|
||||
return idp_pb.SAMLNameIDFormat_SAML_NAME_ID_FORMAT_UNSPECIFIED
|
||||
}
|
||||
}
|
235
internal/api/grpc/idp/v2/query_integration_test.go
Normal file
235
internal/api/grpc/idp/v2/query_integration_test.go
Normal file
@ -0,0 +1,235 @@
|
||||
//go:build integration
|
||||
|
||||
package idp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/idp/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
)
|
||||
|
||||
type idpAttr struct {
|
||||
ID string
|
||||
Name string
|
||||
Details *object.Details
|
||||
}
|
||||
|
||||
func TestServer_GetIDPByID(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
req *idp.GetIDPByIDRequest
|
||||
dep func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *idp.GetIDPByIDResponse
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "idp by ID, no id provided",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&idp.GetIDPByIDRequest{
|
||||
Id: "",
|
||||
},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "idp by ID, not found",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&idp.GetIDPByIDRequest{
|
||||
Id: "unknown",
|
||||
},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "idp by ID, instance, ok",
|
||||
args: args{
|
||||
IamCTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := fmt.Sprintf("GetIDPByID%d", time.Now().UnixNano())
|
||||
resp := Tester.AddGenericOAuthIDP(ctx, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
want: &idp.GetIDPByIDResponse{
|
||||
Idp: &idp.IDP{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
},
|
||||
State: idp.IDPState_IDP_STATE_ACTIVE,
|
||||
Type: idp.IDPType_IDP_TYPE_OAUTH,
|
||||
Config: &idp.IDPConfig{
|
||||
Config: &idp.IDPConfig_Oauth{
|
||||
Oauth: &idp.OAuthConfig{
|
||||
ClientId: "clientID",
|
||||
AuthorizationEndpoint: "https://example.com/oauth/v2/authorize",
|
||||
TokenEndpoint: "https://example.com/oauth/v2/token",
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IdAttribute: "id",
|
||||
},
|
||||
},
|
||||
Options: &idp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "idp by ID, instance, no permission",
|
||||
args: args{
|
||||
UserCTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := fmt.Sprintf("GetIDPByID%d", time.Now().UnixNano())
|
||||
resp := Tester.AddGenericOAuthIDP(IamCTX, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "idp by ID, org, ok",
|
||||
args: args{
|
||||
CTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := fmt.Sprintf("GetIDPByID%d", time.Now().UnixNano())
|
||||
resp := Tester.AddOrgGenericOAuthIDP(ctx, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
want: &idp.GetIDPByIDResponse{
|
||||
Idp: &idp.IDP{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
},
|
||||
State: idp.IDPState_IDP_STATE_ACTIVE,
|
||||
Type: idp.IDPType_IDP_TYPE_OAUTH,
|
||||
Config: &idp.IDPConfig{
|
||||
Config: &idp.IDPConfig_Oauth{
|
||||
Oauth: &idp.OAuthConfig{
|
||||
ClientId: "clientID",
|
||||
AuthorizationEndpoint: "https://example.com/oauth/v2/authorize",
|
||||
TokenEndpoint: "https://example.com/oauth/v2/token",
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IdAttribute: "id",
|
||||
},
|
||||
},
|
||||
Options: &idp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "idp by ID, org, no permission",
|
||||
args: args{
|
||||
UserCTX,
|
||||
&idp.GetIDPByIDRequest{},
|
||||
func(ctx context.Context, request *idp.GetIDPByIDRequest) *idpAttr {
|
||||
name := fmt.Sprintf("GetIDPByID%d", time.Now().UnixNano())
|
||||
resp := Tester.AddOrgGenericOAuthIDP(CTX, name)
|
||||
request.Id = resp.Id
|
||||
return &idpAttr{
|
||||
resp.GetId(),
|
||||
name,
|
||||
&object.Details{
|
||||
Sequence: resp.Details.Sequence,
|
||||
ChangeDate: resp.Details.ChangeDate,
|
||||
ResourceOwner: resp.Details.ResourceOwner,
|
||||
}}
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
idpAttr := tt.args.dep(tt.args.ctx, tt.args.req)
|
||||
retryDuration := time.Minute
|
||||
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||
retryDuration = time.Until(ctxDeadline)
|
||||
}
|
||||
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
got, getErr := Client.GetIDPByID(tt.args.ctx, tt.args.req)
|
||||
assertErr := assert.NoError
|
||||
if tt.wantErr {
|
||||
assertErr = assert.Error
|
||||
}
|
||||
assertErr(ttt, getErr)
|
||||
if getErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// set provided info from creation
|
||||
tt.want.Idp.Details = idpAttr.Details
|
||||
tt.want.Idp.Name = idpAttr.Name
|
||||
tt.want.Idp.Id = idpAttr.ID
|
||||
|
||||
// first check for details, mgmt and admin api don't fill the details correctly
|
||||
integration.AssertDetails(t, tt.want.Idp, got.Idp)
|
||||
// then set details
|
||||
tt.want.Idp.Details = got.Idp.Details
|
||||
// to check the rest of the content
|
||||
assert.Equal(ttt, tt.want.Idp, got.Idp)
|
||||
}, retryDuration, time.Second)
|
||||
})
|
||||
}
|
||||
}
|
56
internal/api/grpc/idp/v2/server.go
Normal file
56
internal/api/grpc/idp/v2/server.go
Normal file
@ -0,0 +1,56 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"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/domain"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/idp/v2"
|
||||
)
|
||||
|
||||
var _ idp.IdentityProviderServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
idp.UnimplementedIdentityProviderServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
|
||||
checkPermission domain.PermissionCheck
|
||||
}
|
||||
|
||||
type Config struct{}
|
||||
|
||||
func CreateServer(
|
||||
command *command.Commands,
|
||||
query *query.Queries,
|
||||
checkPermission domain.PermissionCheck,
|
||||
) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
checkPermission: checkPermission,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
idp.RegisterIdentityProviderServiceServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return idp.IdentityProviderService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return idp.IdentityProviderService_ServiceDesc.ServiceName
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return idp.IdentityProviderService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
|
||||
return idp.RegisterIdentityProviderServiceHandler
|
||||
}
|
40
internal/api/grpc/idp/v2/server_integration_test.go
Normal file
40
internal/api/grpc/idp/v2/server_integration_test.go
Normal file
@ -0,0 +1,40 @@
|
||||
//go:build integration
|
||||
|
||||
package idp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
CTX context.Context
|
||||
IamCTX context.Context
|
||||
UserCTX context.Context
|
||||
SystemCTX context.Context
|
||||
ErrCTX context.Context
|
||||
Tester *integration.Tester
|
||||
Client idp_pb.IdentityProviderServiceClient
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(func() int {
|
||||
ctx, errCtx, cancel := integration.Contexts(time.Hour)
|
||||
defer cancel()
|
||||
|
||||
Tester = integration.NewTester(ctx)
|
||||
defer Tester.Done()
|
||||
|
||||
UserCTX = Tester.WithAuthorization(ctx, integration.Login)
|
||||
IamCTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||||
SystemCTX = Tester.WithAuthorization(ctx, integration.SystemUser)
|
||||
CTX, ErrCTX = Tester.WithAuthorization(ctx, integration.OrgOwner), errCtx
|
||||
Client = Tester.Client.IDPv2
|
||||
return m.Run()
|
||||
}())
|
||||
}
|
@ -149,7 +149,7 @@ func (s *Server) GetProviderByID(ctx context.Context, req *mgmt_pb.GetProviderBy
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, orgIDQuery)
|
||||
idp, err := s.query.IDPTemplateByID(ctx, true, req.Id, false, nil, orgIDQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ func (l *Login) getOrgDomainPolicy(r *http.Request, orgID string) (*query.Domain
|
||||
}
|
||||
|
||||
func (l *Login) getIDPByID(r *http.Request, id string) (*query.IDPTemplate, error) {
|
||||
return l.query.IDPTemplateByID(r.Context(), false, id, false)
|
||||
return l.query.IDPTemplateByID(r.Context(), false, id, false, nil)
|
||||
}
|
||||
|
||||
func (l *Login) getLoginPolicy(r *http.Request, orgID string) (*query.LoginPolicy, error) {
|
||||
|
@ -33,4 +33,6 @@ const (
|
||||
PermissionUserCredentialWrite = "user.credential.write"
|
||||
PermissionSessionWrite = "session.write"
|
||||
PermissionSessionDelete = "session.delete"
|
||||
PermissionIDPRead = "iam.idp.read"
|
||||
PermissionOrgIDPRead = "org.idp.read"
|
||||
)
|
||||
|
@ -24,22 +24,24 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/ldap"
|
||||
openid "github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/saml"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
idp_rp "github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/auth"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
feature_v2beta "github.com/zitadel/zitadel/pkg/grpc/feature/v2beta"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp/v2"
|
||||
mgmt "github.com/zitadel/zitadel/pkg/grpc/management"
|
||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
||||
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
|
||||
oidc_pb_v2beta "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
|
||||
org "github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
org_v2beta "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
|
||||
action "github.com/zitadel/zitadel/pkg/grpc/resources/action/v3alpha"
|
||||
webkey_v3alpha "github.com/zitadel/zitadel/pkg/grpc/resources/webkey/v3alpha"
|
||||
session "github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||
session_v2beta "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
|
||||
settings "github.com/zitadel/zitadel/pkg/grpc/settings/v2"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/settings/v2"
|
||||
settings_v2beta "github.com/zitadel/zitadel/pkg/grpc/settings/v2beta"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/system"
|
||||
user_pb "github.com/zitadel/zitadel/pkg/grpc/user"
|
||||
@ -69,6 +71,7 @@ type Client struct {
|
||||
FeatureV2 feature.FeatureServiceClient
|
||||
UserSchemaV3 schema.UserSchemaServiceClient
|
||||
WebKeyV3Alpha webkey_v3alpha.ZITADELWebKeysClient
|
||||
IDPv2 idp_pb.IdentityProviderServiceClient
|
||||
}
|
||||
|
||||
func newClient(cc *grpc.ClientConn) Client {
|
||||
@ -93,6 +96,7 @@ func newClient(cc *grpc.ClientConn) Client {
|
||||
FeatureV2: feature.NewFeatureServiceClient(cc),
|
||||
UserSchemaV3: schema.NewUserSchemaServiceClient(cc),
|
||||
WebKeyV3Alpha: webkey_v3alpha.NewZITADELWebKeysClient(cc),
|
||||
IDPv2: idp_pb.NewIdentityProviderServiceClient(cc),
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,6 +371,28 @@ func (s *Tester) SetUserPassword(ctx context.Context, userID, password string, c
|
||||
return resp.GetDetails()
|
||||
}
|
||||
|
||||
func (s *Tester) AddGenericOAuthIDP(ctx context.Context, name string) *admin.AddGenericOAuthProviderResponse {
|
||||
resp, err := s.Client.Admin.AddGenericOAuthProvider(ctx, &admin.AddGenericOAuthProviderRequest{
|
||||
Name: name,
|
||||
ClientId: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
AuthorizationEndpoint: "https://example.com/oauth/v2/authorize",
|
||||
TokenEndpoint: "https://example.com/oauth/v2/token",
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IdAttribute: "id",
|
||||
ProviderOptions: &idp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
|
||||
},
|
||||
})
|
||||
logging.OnError(err).Fatal("create generic OAuth idp")
|
||||
return resp
|
||||
}
|
||||
|
||||
func (s *Tester) AddGenericOAuthProvider(t *testing.T, ctx context.Context) string {
|
||||
ctx = authz.WithInstance(ctx, s.Instance)
|
||||
id, _, err := s.Commands.AddInstanceGenericOAuthProvider(ctx, command.GenericOAuthProvider{
|
||||
@ -378,7 +404,7 @@ func (s *Tester) AddGenericOAuthProvider(t *testing.T, ctx context.Context) stri
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IDAttribute: "id",
|
||||
IDPOptions: idp.Options{
|
||||
IDPOptions: idp_rp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
@ -389,6 +415,28 @@ func (s *Tester) AddGenericOAuthProvider(t *testing.T, ctx context.Context) stri
|
||||
return id
|
||||
}
|
||||
|
||||
func (s *Tester) AddOrgGenericOAuthIDP(ctx context.Context, name string) *mgmt.AddGenericOAuthProviderResponse {
|
||||
resp, err := s.Client.Mgmt.AddGenericOAuthProvider(ctx, &mgmt.AddGenericOAuthProviderRequest{
|
||||
Name: name,
|
||||
ClientId: "clientID",
|
||||
ClientSecret: "clientSecret",
|
||||
AuthorizationEndpoint: "https://example.com/oauth/v2/authorize",
|
||||
TokenEndpoint: "https://example.com/oauth/v2/token",
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IdAttribute: "id",
|
||||
ProviderOptions: &idp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
AutoLinking: idp.AutoLinkingOption_AUTO_LINKING_OPTION_USERNAME,
|
||||
},
|
||||
})
|
||||
logging.OnError(err).Fatal("create generic OAuth idp")
|
||||
return resp
|
||||
}
|
||||
|
||||
func (s *Tester) AddOrgGenericOAuthProvider(t *testing.T, ctx context.Context, orgID string) string {
|
||||
ctx = authz.WithInstance(ctx, s.Instance)
|
||||
id, _, err := s.Commands.AddOrgGenericOAuthProvider(ctx, orgID,
|
||||
@ -401,7 +449,7 @@ func (s *Tester) AddOrgGenericOAuthProvider(t *testing.T, ctx context.Context, o
|
||||
UserEndpoint: "https://api.example.com/user",
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
IDAttribute: "id",
|
||||
IDPOptions: idp.Options{
|
||||
IDPOptions: idp_rp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
@ -417,7 +465,7 @@ func (s *Tester) AddSAMLProvider(t *testing.T, ctx context.Context) string {
|
||||
id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{
|
||||
Name: "saml-idp",
|
||||
Metadata: []byte("<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"2023-09-16T09:00:32.986Z\" cacheDuration=\"PT48H\" entityID=\"http://localhost:8000/metadata\">\n <IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <KeyDescriptor use=\"signing\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n </KeyDescriptor>\n <KeyDescriptor use=\"encryption\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod>\n </KeyDescriptor>\n <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n </IDPSSODescriptor>\n</EntityDescriptor>"),
|
||||
IDPOptions: idp.Options{
|
||||
IDPOptions: idp_rp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
@ -435,7 +483,7 @@ func (s *Tester) AddSAMLRedirectProvider(t *testing.T, ctx context.Context, tran
|
||||
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
|
||||
Metadata: []byte("<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"2023-09-16T09:00:32.986Z\" cacheDuration=\"PT48H\" entityID=\"http://localhost:8000/metadata\">\n <IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <KeyDescriptor use=\"signing\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n </KeyDescriptor>\n <KeyDescriptor use=\"encryption\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod>\n </KeyDescriptor>\n <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n </IDPSSODescriptor>\n</EntityDescriptor>"),
|
||||
TransientMappingAttributeName: transientMappingAttributeName,
|
||||
IDPOptions: idp.Options{
|
||||
IDPOptions: idp_rp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
@ -452,7 +500,7 @@ func (s *Tester) AddSAMLPostProvider(t *testing.T, ctx context.Context) string {
|
||||
Name: "saml-idp-post",
|
||||
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
|
||||
Metadata: []byte("<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"2023-09-16T09:00:32.986Z\" cacheDuration=\"PT48H\" entityID=\"http://localhost:8000/metadata\">\n <IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <KeyDescriptor use=\"signing\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n </KeyDescriptor>\n <KeyDescriptor use=\"encryption\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod>\n </KeyDescriptor>\n <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n </IDPSSODescriptor>\n</EntityDescriptor>"),
|
||||
IDPOptions: idp.Options{
|
||||
IDPOptions: idp_rp.Options{
|
||||
IsLinkingAllowed: true,
|
||||
IsCreationAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
|
@ -712,8 +712,29 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// IDPTemplateByID searches for the requested id
|
||||
func (q *Queries) IDPTemplateByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, queries ...SearchQuery) (template *IDPTemplate, err error) {
|
||||
// IDPTemplateByID searches for the requested id with permission check if necessary
|
||||
func (q *Queries) IDPTemplateByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, permissionCheck domain.PermissionCheck, queries ...SearchQuery) (template *IDPTemplate, err error) {
|
||||
idp, err := q.idpTemplateByID(ctx, shouldTriggerBulk, id, withOwnerRemoved, queries...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if permissionCheck != nil {
|
||||
switch idp.OwnerType {
|
||||
case domain.IdentityProviderTypeSystem:
|
||||
if err := permissionCheck(ctx, domain.PermissionIDPRead, idp.ResourceOwner, idp.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case domain.IdentityProviderTypeOrg:
|
||||
if err := permissionCheck(ctx, domain.PermissionOrgIDPRead, idp.ResourceOwner, idp.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return idp, nil
|
||||
}
|
||||
|
||||
// idpTemplateByID searches for the requested id
|
||||
func (q *Queries) idpTemplateByID(ctx context.Context, shouldTriggerBulk bool, id string, withOwnerRemoved bool, queries ...SearchQuery) (template *IDPTemplate, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
|
4
pkg/grpc/idp/v2/idp.go
Normal file
4
pkg/grpc/idp/v2/idp.go
Normal file
@ -0,0 +1,4 @@
|
||||
package idp
|
||||
|
||||
type IsIDPConfig = isIDPConfig_Config
|
||||
type IsAzureADTenantType = isAzureADTenant_Type
|
391
proto/zitadel/idp/v2/idp.proto
Normal file
391
proto/zitadel/idp/v2/idp.proto
Normal file
@ -0,0 +1,391 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.idp.v2;
|
||||
|
||||
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
||||
import "zitadel/object/v2/object.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/idp/v2;idp";
|
||||
|
||||
message IDP {
|
||||
// Unique identifier for the identity provider.
|
||||
string id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"69629023906488334\"";
|
||||
}
|
||||
];
|
||||
zitadel.object.v2.Details details = 2;
|
||||
// Current state of the identity provider.
|
||||
IDPState state = 3;
|
||||
string name = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"Google\"";
|
||||
}
|
||||
];
|
||||
// Type of the identity provider, for example OIDC, JWT, LDAP and SAML.
|
||||
IDPType type = 5;
|
||||
// Configuration for the type of the identity provider.
|
||||
IDPConfig config = 6;
|
||||
}
|
||||
|
||||
enum IDPState {
|
||||
IDP_STATE_UNSPECIFIED = 0;
|
||||
IDP_STATE_ACTIVE = 1;
|
||||
IDP_STATE_INACTIVE = 2;
|
||||
IDP_STATE_REMOVED = 3;
|
||||
IDP_STATE_MIGRATED = 4;
|
||||
}
|
||||
|
||||
enum IDPType {
|
||||
IDP_TYPE_UNSPECIFIED = 0;
|
||||
IDP_TYPE_OIDC = 1;
|
||||
IDP_TYPE_JWT = 2;
|
||||
IDP_TYPE_LDAP = 3;
|
||||
IDP_TYPE_OAUTH = 4;
|
||||
IDP_TYPE_AZURE_AD = 5;
|
||||
IDP_TYPE_GITHUB = 6;
|
||||
IDP_TYPE_GITHUB_ES = 7;
|
||||
IDP_TYPE_GITLAB = 8;
|
||||
IDP_TYPE_GITLAB_SELF_HOSTED = 9;
|
||||
IDP_TYPE_GOOGLE = 10;
|
||||
IDP_TYPE_APPLE = 11;
|
||||
IDP_TYPE_SAML = 12;
|
||||
}
|
||||
|
||||
enum SAMLBinding {
|
||||
SAML_BINDING_UNSPECIFIED = 0;
|
||||
SAML_BINDING_POST = 1;
|
||||
SAML_BINDING_REDIRECT = 2;
|
||||
SAML_BINDING_ARTIFACT = 3;
|
||||
}
|
||||
|
||||
enum SAMLNameIDFormat {
|
||||
SAML_NAME_ID_FORMAT_UNSPECIFIED = 0;
|
||||
SAML_NAME_ID_FORMAT_EMAIL_ADDRESS = 1;
|
||||
SAML_NAME_ID_FORMAT_PERSISTENT = 2;
|
||||
SAML_NAME_ID_FORMAT_TRANSIENT = 3;
|
||||
}
|
||||
|
||||
message IDPConfig {
|
||||
Options options = 1;
|
||||
oneof config {
|
||||
LDAPConfig ldap = 2;
|
||||
GoogleConfig google = 3;
|
||||
OAuthConfig oauth = 4;
|
||||
GenericOIDCConfig oidc = 5;
|
||||
JWTConfig jwt = 6;
|
||||
GitHubConfig github = 7;
|
||||
GitHubEnterpriseServerConfig github_es = 8;
|
||||
GitLabConfig gitlab = 9;
|
||||
GitLabSelfHostedConfig gitlab_self_hosted = 10;
|
||||
AzureADConfig azure_ad = 11;
|
||||
AppleConfig apple = 12;
|
||||
SAMLConfig saml = 13;
|
||||
}
|
||||
}
|
||||
|
||||
message JWTConfig {
|
||||
// The endpoint where the JWT can be extracted.
|
||||
string jwt_endpoint = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://accounts.google.com\"";
|
||||
}
|
||||
];
|
||||
// The issuer of the JWT (for validation).
|
||||
string issuer = 2 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://accounts.google.com\"";
|
||||
}
|
||||
];
|
||||
// The endpoint to the key (JWK) which is used to sign the JWT with.
|
||||
string keys_endpoint = 3 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://accounts.google.com/keys\"";
|
||||
}
|
||||
];
|
||||
// The name of the header where the JWT is sent in, default is authorization.
|
||||
string header_name = 4 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"x-auth-token\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message OAuthConfig {
|
||||
// Client id generated by the identity provider.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The endpoint where ZITADEL send the user to authenticate.
|
||||
string authorization_endpoint = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://accounts.google.com/o/oauth2/v2/auth\"";
|
||||
}
|
||||
];
|
||||
// The endpoint where ZITADEL can get the token.
|
||||
string token_endpoint = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://oauth2.googleapis.com/token\"";
|
||||
}
|
||||
];
|
||||
// The endpoint where ZITADEL can get the user information.
|
||||
string user_endpoint = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://openidconnect.googleapis.com/v1/userinfo\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request on the identity provider.
|
||||
repeated string scopes = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
// Defines how the attribute is called where ZITADEL can get the id of the user.
|
||||
string id_attribute = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"user_id\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GenericOIDCConfig {
|
||||
// The OIDC issuer of the identity provider.
|
||||
string issuer = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"https://accounts.google.com/\"";
|
||||
}
|
||||
];
|
||||
// Client id generated by the identity provider.
|
||||
string client_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request on the identity provider.
|
||||
repeated string scopes = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
// If true, provider information get mapped from the id token, not from the userinfo endpoint.
|
||||
bool is_id_token_mapping = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "true";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GitHubConfig {
|
||||
// The client ID of the GitHub App.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request to GitHub.
|
||||
repeated string scopes = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GitHubEnterpriseServerConfig {
|
||||
// The client ID of the GitHub App.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
string authorization_endpoint = 2;
|
||||
string token_endpoint = 3;
|
||||
string user_endpoint = 4;
|
||||
// The scopes requested by ZITADEL during the request to GitHub.
|
||||
repeated string scopes = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GoogleConfig {
|
||||
// Client id of the Google application.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request to Google.
|
||||
repeated string scopes = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GitLabConfig {
|
||||
// Client id of the GitLab application.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request to GitLab.
|
||||
repeated string scopes = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GitLabSelfHostedConfig {
|
||||
string issuer = 1;
|
||||
// Client id of the GitLab application.
|
||||
string client_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request to GitLab.
|
||||
repeated string scopes = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message LDAPConfig {
|
||||
repeated string servers = 1;
|
||||
bool start_tls = 2;
|
||||
string base_dn = 3;
|
||||
string bind_dn = 4;
|
||||
string user_base = 5;
|
||||
repeated string user_object_classes = 6;
|
||||
repeated string user_filters = 7;
|
||||
google.protobuf.Duration timeout = 8;
|
||||
LDAPAttributes attributes = 9;
|
||||
}
|
||||
|
||||
message SAMLConfig {
|
||||
// Metadata of the SAML identity provider.
|
||||
bytes metadata_xml = 1;
|
||||
// Binding which defines the type of communication with the identity provider.
|
||||
SAMLBinding binding = 2;
|
||||
// Boolean which defines if the authentication requests are signed.
|
||||
bool with_signed_request = 3;
|
||||
// `nameid-format` for the SAML Request.
|
||||
SAMLNameIDFormat name_id_format = 4;
|
||||
// Optional name of the attribute, which will be used to map the user
|
||||
// in case the nameid-format returned is `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`.
|
||||
optional string transient_mapping_attribute_name = 5;
|
||||
}
|
||||
|
||||
message AzureADConfig {
|
||||
// Client id of the Azure AD application
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"client-id\"";
|
||||
}
|
||||
];
|
||||
// Defines what user accounts should be able to login (Personal, Organizational, All).
|
||||
AzureADTenant tenant = 2;
|
||||
// Azure AD doesn't send if the email has been verified. Enable this if the user email should always be added verified in ZITADEL (no verification emails will be sent).
|
||||
bool email_verified = 3;
|
||||
// The scopes requested by ZITADEL during the request to Azure AD.
|
||||
repeated string scopes = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"openid\", \"profile\", \"email\", \"User.Read\"]";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message Options {
|
||||
// Enable if users should be able to link an existing ZITADEL user with an external account.
|
||||
bool is_linking_allowed = 1;
|
||||
// Enable if users should be able to create a new account in ZITADEL when using an external account.
|
||||
bool is_creation_allowed = 2;
|
||||
// Enable if a new account in ZITADEL should be created automatically when login with an external account.
|
||||
bool is_auto_creation = 3;
|
||||
// Enable if a the ZITADEL account fields should be updated automatically on each login.
|
||||
bool is_auto_update = 4;
|
||||
// Enable if users should get prompted to link an existing ZITADEL user to an external account if the selected attribute matches.
|
||||
AutoLinkingOption auto_linking = 5 ;
|
||||
}
|
||||
|
||||
enum AutoLinkingOption {
|
||||
// AUTO_LINKING_OPTION_UNSPECIFIED disables the auto linking prompt.
|
||||
AUTO_LINKING_OPTION_UNSPECIFIED = 0;
|
||||
// AUTO_LINKING_OPTION_USERNAME will use the username of the external user to check for a corresponding ZITADEL user.
|
||||
AUTO_LINKING_OPTION_USERNAME = 1;
|
||||
// AUTO_LINKING_OPTION_EMAIL will use the email of the external user to check for a corresponding ZITADEL user with the same verified email
|
||||
// Note that in case multiple users match, no prompt will be shown.
|
||||
AUTO_LINKING_OPTION_EMAIL = 2;
|
||||
}
|
||||
|
||||
message LDAPAttributes {
|
||||
string id_attribute = 1 [(validate.rules).string = {max_len: 200}];
|
||||
string first_name_attribute = 2 [(validate.rules).string = {max_len: 200}];
|
||||
string last_name_attribute = 3 [(validate.rules).string = {max_len: 200}];
|
||||
string display_name_attribute = 4 [(validate.rules).string = {max_len: 200}];
|
||||
string nick_name_attribute = 5 [(validate.rules).string = {max_len: 200}];
|
||||
string preferred_username_attribute = 6 [(validate.rules).string = {max_len: 200}];
|
||||
string email_attribute = 7 [(validate.rules).string = {max_len: 200}];
|
||||
string email_verified_attribute = 8 [(validate.rules).string = {max_len: 200}];
|
||||
string phone_attribute = 9 [(validate.rules).string = {max_len: 200}];
|
||||
string phone_verified_attribute = 10 [(validate.rules).string = {max_len: 200}];
|
||||
string preferred_language_attribute = 11 [(validate.rules).string = {max_len: 200}];
|
||||
string avatar_url_attribute = 12 [(validate.rules).string = {max_len: 200}];
|
||||
string profile_attribute = 13 [(validate.rules).string = {max_len: 200}];
|
||||
}
|
||||
|
||||
enum AzureADTenantType {
|
||||
AZURE_AD_TENANT_TYPE_COMMON = 0;
|
||||
AZURE_AD_TENANT_TYPE_ORGANISATIONS = 1;
|
||||
AZURE_AD_TENANT_TYPE_CONSUMERS = 2;
|
||||
}
|
||||
|
||||
message AzureADTenant {
|
||||
oneof type {
|
||||
AzureADTenantType tenant_type = 1;
|
||||
string tenant_id = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message AppleConfig {
|
||||
// Client id (App ID or Service ID) provided by Apple.
|
||||
string client_id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"com.client.id\"";
|
||||
}
|
||||
];
|
||||
// Team ID provided by Apple.
|
||||
string team_id = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"ALT03JV3OS\"";
|
||||
}
|
||||
];
|
||||
// ID of the private key generated by Apple.
|
||||
string key_id = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "\"OGKDK25KD\"";
|
||||
}
|
||||
];
|
||||
// The scopes requested by ZITADEL during the request to Apple.
|
||||
repeated string scopes = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
example: "[\"name\", \"email\"]";
|
||||
}
|
||||
];
|
||||
}
|
136
proto/zitadel/idp/v2/idp_service.proto
Normal file
136
proto/zitadel/idp/v2/idp_service.proto
Normal file
@ -0,0 +1,136 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.idp.v2;
|
||||
|
||||
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
||||
import "zitadel/object/v2/object.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
import "zitadel/idp/v2/idp.proto";
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/idp/v2;idp";
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
info: {
|
||||
title: "Identity Provider Service";
|
||||
version: "2.0";
|
||||
description: "This API is intended to manage identity providers (IdPs) in a ZITADEL instance.";
|
||||
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: "$CUSTOM-DOMAIN";
|
||||
base_path: "/";
|
||||
|
||||
external_docs: {
|
||||
description: "Detailed information about ZITADEL",
|
||||
url: "https://zitadel.com/docs"
|
||||
}
|
||||
security_definitions: {
|
||||
security: {
|
||||
key: "OAuth2";
|
||||
value: {
|
||||
type: TYPE_OAUTH2;
|
||||
flow: FLOW_ACCESS_CODE;
|
||||
authorization_url: "$CUSTOM-DOMAIN/oauth/v2/authorize";
|
||||
token_url: "$CUSTOM-DOMAIN/oauth/v2/token";
|
||||
scopes: {
|
||||
scope: {
|
||||
key: "openid";
|
||||
value: "openid";
|
||||
}
|
||||
scope: {
|
||||
key: "urn:zitadel:iam:org:project:id:zitadel:aud";
|
||||
value: "urn:zitadel:iam:org:project:id:zitadel:aud";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
security: {
|
||||
security_requirement: {
|
||||
key: "OAuth2";
|
||||
value: {
|
||||
scope: "openid";
|
||||
scope: "urn:zitadel:iam:org:project:id:zitadel:aud";
|
||||
}
|
||||
}
|
||||
}
|
||||
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 IdentityProviderService {
|
||||
|
||||
// Get identity provider (IdP) by ID
|
||||
//
|
||||
// Returns an identity provider (social/enterprise login) by its ID, which can be of the type Google, AzureAD, etc.
|
||||
rpc GetIDPByID (GetIDPByIDRequest) returns (GetIDPByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v2/idps/{id}"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message GetIDPByIDRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
}
|
||||
|
||||
message GetIDPByIDResponse {
|
||||
zitadel.idp.v2.IDP idp = 1;
|
||||
}
|
@ -47,7 +47,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
consumes: "application/grpc-web+proto";
|
||||
produces: "application/grpc-web+proto";
|
||||
|
||||
host: "${ZITADEL_DOMAIN}";
|
||||
host: "$CUSTOM-DOMAIN";
|
||||
base_path: "/resources/v3alpha/actions";
|
||||
|
||||
external_docs: {
|
||||
@ -60,8 +60,8 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
value: {
|
||||
type: TYPE_OAUTH2;
|
||||
flow: FLOW_ACCESS_CODE;
|
||||
authorization_url: "${ZITADEL_DOMAIN}/oauth/v2/authorize";
|
||||
token_url: "${ZITADEL_DOMAIN}/oauth/v2/token";
|
||||
authorization_url: "$CUSTOM-DOMAIN/oauth/v2/authorize";
|
||||
token_url: "$CUSTOM-DOMAIN/oauth/v2/token";
|
||||
scopes: {
|
||||
scope: {
|
||||
key: "openid";
|
||||
@ -135,7 +135,7 @@ service ZITADELActions {
|
||||
description: "Target successfully created";
|
||||
schema: {
|
||||
json_schema: {
|
||||
ref: "#/definitions/CreateTargetResponse";
|
||||
ref: "#/definitions/v3alphaCreateTargetResponse";
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -278,7 +278,7 @@ service ZITADELActions {
|
||||
description: "Execution successfully updated or left unchanged";
|
||||
schema: {
|
||||
json_schema: {
|
||||
ref: "#/definitions/SetExecutionResponse";
|
||||
ref: "#/definitions/v3alphaSetExecutionResponse";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
consumes: "application/grpc-web+proto";
|
||||
produces: "application/grpc-web+proto";
|
||||
|
||||
host: "${ZITADEL_DOMAIN}";
|
||||
host: "$CUSTOM-DOMAIN";
|
||||
base_path: "/resources/v3alpha/web_keys";
|
||||
|
||||
external_docs: {
|
||||
|
Loading…
Reference in New Issue
Block a user