mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-04 23:45:07 +00:00
feat: add management for ldap idp template (#5220)
Add management functionality for LDAP idps with templates and the basic functionality for the LDAP provider, which can then be used with a separate login page in the future. --------- Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
parent
058192c22b
commit
586495a0be
@ -568,6 +568,68 @@ all fields are updated. If no value is provided the field will be empty afterwar
|
||||
PUT: /idps/{idp_id}/jwt_config
|
||||
|
||||
|
||||
### ListProviders
|
||||
|
||||
> **rpc** ListProviders([ListProvidersRequest](#listprovidersrequest))
|
||||
[ListProvidersResponse](#listprovidersresponse)
|
||||
|
||||
Returns all identity providers, which match the query
|
||||
Limit should always be set, there is a default limit set by the service
|
||||
|
||||
|
||||
|
||||
POST: /idps/templates/_search
|
||||
|
||||
|
||||
### GetProviderByID
|
||||
|
||||
> **rpc** GetProviderByID([GetProviderByIDRequest](#getproviderbyidrequest))
|
||||
[GetProviderByIDResponse](#getproviderbyidresponse)
|
||||
|
||||
Returns an identity provider of the instance
|
||||
|
||||
|
||||
|
||||
GET: /idps/templates/{id}
|
||||
|
||||
|
||||
### AddLDAPProvider
|
||||
|
||||
> **rpc** AddLDAPProvider([AddLDAPProviderRequest](#addldapproviderrequest))
|
||||
[AddLDAPProviderResponse](#addldapproviderresponse)
|
||||
|
||||
Add a new ldap identity provider on the instance
|
||||
|
||||
|
||||
|
||||
POST: /idps/ldap
|
||||
|
||||
|
||||
### UpdateLDAPProvider
|
||||
|
||||
> **rpc** UpdateLDAPProvider([UpdateLDAPProviderRequest](#updateldapproviderrequest))
|
||||
[UpdateLDAPProviderResponse](#updateldapproviderresponse)
|
||||
|
||||
Change an existing ldap identity provider on the instance
|
||||
|
||||
|
||||
|
||||
POST: /idps/ldap/{id}
|
||||
|
||||
|
||||
### DeleteProvider
|
||||
|
||||
> **rpc** DeleteProvider([DeleteProviderRequest](#deleteproviderrequest))
|
||||
[DeleteProviderResponse](#deleteproviderresponse)
|
||||
|
||||
Remove an identity provider
|
||||
Will remove all linked providers of this configuration on the users
|
||||
|
||||
|
||||
|
||||
POST: /idps/templates/{id}
|
||||
|
||||
|
||||
### GetOrgIAMPolicy
|
||||
|
||||
> **rpc** GetOrgIAMPolicy([GetOrgIAMPolicyRequest](#getorgiampolicyrequest))
|
||||
@ -1861,6 +1923,39 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### AddLDAPProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| host | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| port | string | - | string.max_len: 5<br /> |
|
||||
| tls | bool | - | |
|
||||
| base_dn | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_object_class | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_unique_attribute | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| admin | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| password | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| attributes | zitadel.idp.v1.LDAPAttributes | - | |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddLDAPProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
| id | string | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddMultiFactorToLoginPolicyRequest
|
||||
|
||||
|
||||
@ -2124,6 +2219,28 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### DeleteProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### DeleteProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ExportDataRequest
|
||||
|
||||
|
||||
@ -2924,6 +3041,28 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### GetProviderByIDRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetProviderByIDResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| idp | zitadel.idp.v1.Provider | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetSMSProviderRequest
|
||||
|
||||
|
||||
@ -3541,6 +3680,30 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### ListProvidersRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| query | zitadel.v1.ListQuery | list limitations and ordering | |
|
||||
| queries | repeated ProviderQuery | criteria the client is looking for | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ListProvidersResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.idp.v1.Provider | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ListSMSProvidersRequest
|
||||
|
||||
|
||||
@ -3605,6 +3768,18 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### ProviderQuery
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.idp_id_query | zitadel.idp.v1.IDPIDQuery | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.idp_name_query | zitadel.idp.v1.IDPNameQuery | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ReactivateIDPRequest
|
||||
|
||||
|
||||
@ -4715,6 +4890,39 @@ this is en empty request
|
||||
|
||||
|
||||
|
||||
### UpdateLDAPProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| host | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| port | string | - | string.max_len: 5<br /> |
|
||||
| tls | bool | - | |
|
||||
| base_dn | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_object_class | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_unique_attribute | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| admin | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| password | string | - | string.max_len: 200<br /> |
|
||||
| attributes | zitadel.idp.v1.LDAPAttributes | - | |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateLDAPProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateLabelPolicyRequest
|
||||
|
||||
|
||||
|
@ -105,6 +105,48 @@ title: zitadel/idp.proto
|
||||
|
||||
|
||||
|
||||
### LDAPAttributes
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id_attribute | string | - | string.max_len: 200<br /> |
|
||||
| first_name_attribute | string | - | string.max_len: 200<br /> |
|
||||
| last_name_attribute | string | - | string.max_len: 200<br /> |
|
||||
| display_name_attribute | string | - | string.max_len: 200<br /> |
|
||||
| nick_name_attribute | string | - | string.max_len: 200<br /> |
|
||||
| preferred_username_attribute | string | - | string.max_len: 200<br /> |
|
||||
| email_attribute | string | - | string.max_len: 200<br /> |
|
||||
| email_verified_attribute | string | - | string.max_len: 200<br /> |
|
||||
| phone_attribute | string | - | string.max_len: 200<br /> |
|
||||
| phone_verified_attribute | string | - | string.max_len: 200<br /> |
|
||||
| preferred_language_attribute | string | - | string.max_len: 200<br /> |
|
||||
| avatar_url_attribute | string | - | string.max_len: 200<br /> |
|
||||
| profile_attribute | string | - | string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### LDAPConfig
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| host | string | - | |
|
||||
| port | string | - | |
|
||||
| tls | bool | - | |
|
||||
| base_dn | string | - | |
|
||||
| user_object_class | string | - | |
|
||||
| user_unique_attribute | string | - | |
|
||||
| admin | string | - | |
|
||||
| attributes | LDAPAttributes | - | |
|
||||
| provider_options | Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### OIDCConfig
|
||||
|
||||
|
||||
@ -120,6 +162,49 @@ title: zitadel/idp.proto
|
||||
|
||||
|
||||
|
||||
### Options
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| is_linking_allowed | bool | - | |
|
||||
| is_creation_allowed | bool | - | |
|
||||
| is_auto_creation | bool | - | |
|
||||
| is_auto_update | bool | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### Provider
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
| state | IDPState | - | |
|
||||
| name | string | - | |
|
||||
| owner | IDPOwnerType | - | |
|
||||
| type | ProviderType | - | |
|
||||
| config | ProviderConfig | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ProviderConfig
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| options | Options | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.ldap | LDAPConfig | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Enums
|
||||
@ -195,3 +280,23 @@ authorization framework of the identity provider
|
||||
|
||||
|
||||
|
||||
### ProviderType {#providertype}
|
||||
|
||||
|
||||
| Name | Number | Description |
|
||||
| ---- | ------ | ----------- |
|
||||
| PROVIDER_TYPE_UNSPECIFIED | 0 | - |
|
||||
| PROVIDER_TYPE_OIDC | 1 | - |
|
||||
| PROVIDER_TYPE_JWT | 2 | - |
|
||||
| PROVIDER_TYPE_LDAP | 3 | - |
|
||||
| PROVIDER_TYPE_OAUTH | 4 | - |
|
||||
| PROVIDER_TYPE_AZURE_AD | 5 | - |
|
||||
| PROVIDER_TYPE_GITHUB | 6 | - |
|
||||
| PROVIDER_TYPE_GITHUB_EE | 7 | - |
|
||||
| PROVIDER_TYPE_GITLAB | 8 | - |
|
||||
| PROVIDER_TYPE_GITLAB_SELF_HOSTED | 9 | - |
|
||||
| PROVIDER_TYPE_GOOGLE | 10 | - |
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3025,6 +3025,68 @@ Change JWT identity provider configuration of the organisation
|
||||
PUT: /idps/{idp_id}/jwt_config
|
||||
|
||||
|
||||
### ListProviders
|
||||
|
||||
> **rpc** ListProviders([ListProvidersRequest](#listprovidersrequest))
|
||||
[ListProvidersResponse](#listprovidersresponse)
|
||||
|
||||
Returns all identity providers, which match the query
|
||||
Limit should always be set, there is a default limit set by the service
|
||||
|
||||
|
||||
|
||||
POST: /idps/templates/_search
|
||||
|
||||
|
||||
### GetProviderByID
|
||||
|
||||
> **rpc** GetProviderByID([GetProviderByIDRequest](#getproviderbyidrequest))
|
||||
[GetProviderByIDResponse](#getproviderbyidresponse)
|
||||
|
||||
Returns an identity provider of the organisation
|
||||
|
||||
|
||||
|
||||
GET: /idps/templates/{id}
|
||||
|
||||
|
||||
### AddLDAPProvider
|
||||
|
||||
> **rpc** AddLDAPProvider([AddLDAPProviderRequest](#addldapproviderrequest))
|
||||
[AddLDAPProviderResponse](#addldapproviderresponse)
|
||||
|
||||
Add a new ldap identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
POST: /idps/ldap
|
||||
|
||||
|
||||
### UpdateLDAPProvider
|
||||
|
||||
> **rpc** UpdateLDAPProvider([UpdateLDAPProviderRequest](#updateldapproviderrequest))
|
||||
[UpdateLDAPProviderResponse](#updateldapproviderresponse)
|
||||
|
||||
Change an existing ldap identity provider in the organisation
|
||||
|
||||
|
||||
|
||||
POST: /idps/ldap/{id}
|
||||
|
||||
|
||||
### DeleteProvider
|
||||
|
||||
> **rpc** DeleteProvider([DeleteProviderRequest](#deleteproviderrequest))
|
||||
[DeleteProviderResponse](#deleteproviderresponse)
|
||||
|
||||
Remove an identity provider
|
||||
Will remove all linked providers of this configuration on the users
|
||||
|
||||
|
||||
|
||||
POST: /idps/templates/{id}
|
||||
|
||||
|
||||
### ListActions
|
||||
|
||||
> **rpc** ListActions([ListActionsRequest](#listactionsrequest))
|
||||
@ -3551,6 +3613,39 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### AddLDAPProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| host | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| port | string | - | string.max_len: 5<br /> |
|
||||
| tls | bool | - | |
|
||||
| base_dn | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_object_class | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_unique_attribute | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| admin | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| password | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| attributes | zitadel.idp.v1.LDAPAttributes | - | |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddLDAPProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
| id | string | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### AddMachineKeyRequest
|
||||
|
||||
|
||||
@ -4450,6 +4545,28 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### DeleteProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### DeleteProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GenerateMachineSecretRequest
|
||||
|
||||
|
||||
@ -5539,6 +5656,28 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### GetProviderByIDRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetProviderByIDResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| idp | zitadel.idp.v1.Provider | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### GetSupportedLanguagesRequest
|
||||
This is an empty request
|
||||
|
||||
@ -6544,6 +6683,30 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### ListProvidersRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| query | zitadel.v1.ListQuery | list limitations and ordering | |
|
||||
| queries | repeated ProviderQuery | criteria the client is looking for | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ListProvidersResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ListDetails | - | |
|
||||
| result | repeated zitadel.idp.v1.Provider | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ListUserChangesRequest
|
||||
|
||||
|
||||
@ -6689,6 +6852,19 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### ProviderQuery
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.idp_id_query | zitadel.idp.v1.IDPIDQuery | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.idp_name_query | zitadel.idp.v1.IDPNameQuery | - | |
|
||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.owner_type_query | zitadel.idp.v1.IDPOwnerTypeQuery | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### ReactivateActionRequest
|
||||
|
||||
|
||||
@ -8760,6 +8936,39 @@ This is an empty request
|
||||
|
||||
|
||||
|
||||
### UpdateLDAPProviderRequest
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| id | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| host | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| port | string | - | string.max_len: 5<br /> |
|
||||
| tls | bool | - | |
|
||||
| base_dn | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_object_class | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| user_unique_attribute | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| admin | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||
| password | string | - | string.max_len: 200<br /> |
|
||||
| attributes | zitadel.idp.v1.LDAPAttributes | - | |
|
||||
| provider_options | zitadel.idp.v1.Options | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateLDAPProviderResponse
|
||||
|
||||
|
||||
|
||||
| Field | Type | Description | Validation |
|
||||
| ----- | ---- | ----------- | ----------- |
|
||||
| details | zitadel.v1.ObjectDetails | - | |
|
||||
|
||||
|
||||
|
||||
|
||||
### UpdateMachineRequest
|
||||
|
||||
|
||||
|
11
go.mod
11
go.mod
@ -20,6 +20,7 @@ require (
|
||||
github.com/drone/envsubst v1.0.3
|
||||
github.com/duo-labs/webauthn v0.0.0-20211216225436-9a12cd078b8a
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.7
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/golang/glog v1.0.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
@ -69,11 +70,11 @@ require (
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.25.0
|
||||
go.opentelemetry.io/otel/sdk/metric v0.25.0
|
||||
go.opentelemetry.io/otel/trace v1.2.0
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||
golang.org/x/net v0.5.0
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/net v0.6.0
|
||||
golang.org/x/oauth2 v0.4.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/text v0.6.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.org/x/tools v0.1.13-0.20220928184430-f80e98464e27
|
||||
google.golang.org/api v0.106.0
|
||||
google.golang.org/genproto v0.0.0-20230106154932-a12b697841d9
|
||||
@ -89,6 +90,7 @@ require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.10.0 // indirect
|
||||
cloud.google.com/go/trace v1.4.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/amdonov/xmlsig v0.1.0 // indirect
|
||||
@ -113,6 +115,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.2.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
|
||||
github.com/go-errors/errors v1.0.2 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
|
||||
@ -187,7 +190,7 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v0.10.0 // indirect
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.4.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
|
27
go.sum
27
go.sum
@ -65,6 +65,9 @@ cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5og
|
||||
cloud.google.com/go/trace v1.4.0 h1:qO9eLn2esajC9sxpqp1YKX37nXC3L4BfGnPS0Cx9dYo=
|
||||
cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
@ -264,6 +267,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.0.2 h1:xMxH9j2fNg/L4hLn/4y3M0IUsn0M6Wbu/Uh9QlOfBh4=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
@ -274,6 +279,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs=
|
||||
github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
@ -871,6 +878,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
@ -906,8 +914,6 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/zitadel/logging v0.3.4 h1:9hZsTjMMTE3X2LUi0xcF9Q9EdLo+FAezeu52ireBbHM=
|
||||
github.com/zitadel/logging v0.3.4/go.mod h1:aPpLQhE+v6ocNK0TWrBrd363hZ95KcI17Q1ixAQwZF0=
|
||||
github.com/zitadel/oidc/v2 v2.0.0-dynamic-issuer.7 h1:CGs4gdoSrZZyZM5pGeXCf8FH12r4r8hpJL/wUR3PxRA=
|
||||
github.com/zitadel/oidc/v2 v2.0.0-dynamic-issuer.7/go.mod h1:2jHMP6o/WK0EmcNJkz+FSpjeqcCuQG9YqqqzKZkfgIE=
|
||||
github.com/zitadel/oidc/v2 v2.0.0-dynamic-issuer.8 h1:e6sRhY3Lijku8XBzazLoWpJcjO/EniEA7C5UEgiApRY=
|
||||
github.com/zitadel/oidc/v2 v2.0.0-dynamic-issuer.8/go.mod h1:2jHMP6o/WK0EmcNJkz+FSpjeqcCuQG9YqqqzKZkfgIE=
|
||||
github.com/zitadel/saml v0.0.9 h1:q7FRu52Wm2S5rsSGuzR2nYhEClvexga8bwnGrBL7Bbw=
|
||||
@ -1002,8 +1008,9 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@ -1102,8 +1109,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@ -1226,8 +1233,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@ -1242,8 +1249,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -150,3 +150,57 @@ func (s *Server) UpdateIDPJWTConfig(ctx context.Context, req *admin_pb.UpdateIDP
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetProviderByID(ctx context.Context, req *admin_pb.GetProviderByIDRequest) (*admin_pb.GetProviderByIDResponse, error) {
|
||||
idp, err := s.query.IDPTemplateByIDAndResourceOwner(ctx, true, req.Id, authz.GetInstance(ctx).InstanceID(), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetProviderByIDResponse{Idp: idp_grpc.ProviderToPb(idp)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListProviders(ctx context.Context, req *admin_pb.ListProvidersRequest) (*admin_pb.ListProvidersResponse, error) {
|
||||
queries, err := listProvidersToQuery(authz.GetInstance(ctx).InstanceID(), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := s.query.IDPTemplates(ctx, queries, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.ListProvidersResponse{
|
||||
Result: idp_grpc.ProvidersToPb(resp.Templates),
|
||||
Details: object_pb.ToListDetails(resp.Count, resp.Sequence, resp.Timestamp),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddLDAPProvider(ctx context.Context, req *admin_pb.AddLDAPProviderRequest) (*admin_pb.AddLDAPProviderResponse, error) {
|
||||
id, details, err := s.command.AddInstanceLDAPProvider(ctx, addLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.AddLDAPProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateLDAPProvider(ctx context.Context, req *admin_pb.UpdateLDAPProviderRequest) (*admin_pb.UpdateLDAPProviderResponse, error) {
|
||||
details, err := s.command.UpdateInstanceLDAPProvider(ctx, req.Id, updateLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.UpdateLDAPProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteProvider(ctx context.Context, req *admin_pb.DeleteProviderRequest) (*admin_pb.DeleteProviderResponse, error) {
|
||||
details, err := s.command.DeleteInstanceProvider(ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.DeleteProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package admin
|
||||
import (
|
||||
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -155,3 +156,79 @@ func idpUserLinksToDomain(idps []*query.IDPUserLink) []*domain.UserIDPLink {
|
||||
}
|
||||
return externalIDPs
|
||||
}
|
||||
|
||||
func listProvidersToQuery(instanceID string, req *admin_pb.ListProvidersRequest) (*query.IDPTemplateSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||
queries, err := providerQueriesToQuery(req.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iamQuery, err := query.NewIDPTemplateResourceOwnerSearchQuery(instanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries = append(queries, iamQuery)
|
||||
return &query.IDPTemplateSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func providerQueriesToQuery(queries []*admin_pb.ProviderQuery) (q []query.SearchQuery, err error) {
|
||||
q = make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = providerQueryToQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func providerQueryToQuery(idpQuery *admin_pb.ProviderQuery) (query.SearchQuery, error) {
|
||||
switch q := idpQuery.Query.(type) {
|
||||
case *admin_pb.ProviderQuery_IdpNameQuery:
|
||||
return query.NewIDPTemplateNameSearchQuery(object.TextMethodToQuery(q.IdpNameQuery.Method), q.IdpNameQuery.Name)
|
||||
case *admin_pb.ProviderQuery_IdpIdQuery:
|
||||
return query.NewIDPTemplateIDSearchQuery(q.IdpIdQuery.Id)
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgument(nil, "ADMIN-Dr2aa", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func addLDAPProviderToCommand(req *admin_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateLDAPProviderToCommand(req *admin_pb.UpdateLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||
)
|
||||
|
||||
@ -296,3 +297,142 @@ func ownerTypeToPB(typ domain.IdentityProviderType) idp_pb.IDPOwnerType {
|
||||
return idp_pb.IDPOwnerType_IDP_OWNER_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func OptionsToCommand(options *idp_pb.Options) idp.Options {
|
||||
if options == nil {
|
||||
return idp.Options{}
|
||||
}
|
||||
return idp.Options{
|
||||
IsCreationAllowed: options.IsCreationAllowed,
|
||||
IsLinkingAllowed: options.IsLinkingAllowed,
|
||||
IsAutoCreation: options.IsAutoCreation,
|
||||
IsAutoUpdate: options.IsAutoUpdate,
|
||||
}
|
||||
}
|
||||
|
||||
func LDAPAttributesToCommand(attributes *idp_pb.LDAPAttributes) idp.LDAPAttributes {
|
||||
if attributes == nil {
|
||||
return idp.LDAPAttributes{}
|
||||
}
|
||||
return idp.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 ProvidersToPb(providers []*query.IDPTemplate) []*idp_pb.Provider {
|
||||
list := make([]*idp_pb.Provider, len(providers))
|
||||
for i, provider := range providers {
|
||||
list[i] = ProviderToPb(provider)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func ProviderToPb(provider *query.IDPTemplate) *idp_pb.Provider {
|
||||
return &idp_pb.Provider{
|
||||
Id: provider.ID,
|
||||
Details: obj_grpc.ToViewDetailsPb(provider.Sequence, provider.CreationDate, provider.ChangeDate, provider.ResourceOwner),
|
||||
State: providerStateToPb(provider.State),
|
||||
Name: provider.Name,
|
||||
Owner: ownerTypeToPB(provider.OwnerType),
|
||||
Type: providerTypeToPb(provider.Type),
|
||||
Config: configToPb(provider),
|
||||
}
|
||||
}
|
||||
|
||||
func providerStateToPb(state domain.IDPState) idp_pb.IDPState {
|
||||
switch state { //nolint:exhaustive
|
||||
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
|
||||
default:
|
||||
return idp_pb.IDPState_IDP_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func providerTypeToPb(idpType domain.IDPType) idp_pb.ProviderType {
|
||||
switch idpType {
|
||||
case domain.IDPTypeOIDC:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_OIDC
|
||||
case domain.IDPTypeJWT:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_JWT
|
||||
case domain.IDPTypeOAuth:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_OAUTH
|
||||
case domain.IDPTypeLDAP:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_LDAP
|
||||
case domain.IDPTypeAzureAD:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_AZURE_AD
|
||||
case domain.IDPTypeGitHub:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_GITHUB
|
||||
case domain.IDPTypeGitHubEE:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_GITHUB_EE
|
||||
case domain.IDPTypeGitLab:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_GITLAB
|
||||
case domain.IDPTypeGitLabSelfHosted:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_GITLAB_SELF_HOSTED
|
||||
case domain.IDPTypeGoogle:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_GOOGLE
|
||||
case domain.IDPTypeUnspecified:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_UNSPECIFIED
|
||||
default:
|
||||
return idp_pb.ProviderType_PROVIDER_TYPE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func configToPb(config *query.IDPTemplate) *idp_pb.ProviderConfig {
|
||||
providerConfig := &idp_pb.ProviderConfig{
|
||||
Options: &idp_pb.Options{
|
||||
IsLinkingAllowed: config.IsLinkingAllowed,
|
||||
IsCreationAllowed: config.IsCreationAllowed,
|
||||
IsAutoCreation: config.IsAutoCreation,
|
||||
IsAutoUpdate: config.IsAutoUpdate,
|
||||
},
|
||||
}
|
||||
if config.LDAPIDPTemplate != nil {
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Ldap{
|
||||
Ldap: &idp_pb.LDAPConfig{
|
||||
Host: config.Host,
|
||||
Port: config.Port,
|
||||
Tls: config.TLS,
|
||||
BaseDn: config.BaseDN,
|
||||
UserObjectClass: config.UserObjectClass,
|
||||
UserUniqueAttribute: config.UserUniqueAttribute,
|
||||
Admin: config.Admin,
|
||||
Attributes: ldapAttributesToPb(config.LDAPAttributes),
|
||||
},
|
||||
}
|
||||
}
|
||||
return providerConfig
|
||||
}
|
||||
|
||||
func ldapAttributesToPb(attributes idp.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,
|
||||
}
|
||||
}
|
||||
|
@ -142,3 +142,57 @@ func (s *Server) UpdateOrgIDPJWTConfig(ctx context.Context, req *mgmt_pb.UpdateO
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetProviderByID(ctx context.Context, req *mgmt_pb.GetProviderByIDRequest) (*mgmt_pb.GetProviderByIDResponse, error) {
|
||||
idp, err := s.query.IDPTemplateByIDAndResourceOwner(ctx, true, req.Id, authz.GetCtxData(ctx).OrgID, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.GetProviderByIDResponse{Idp: idp_grpc.ProviderToPb(idp)}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListProviders(ctx context.Context, req *mgmt_pb.ListProvidersRequest) (*mgmt_pb.ListProvidersResponse, error) {
|
||||
queries, err := listProvidersToQuery(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := s.query.IDPTemplates(ctx, queries, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.ListProvidersResponse{
|
||||
Result: idp_grpc.ProvidersToPb(resp.Templates),
|
||||
Details: object_pb.ToListDetails(resp.Count, resp.Sequence, resp.Timestamp),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddLDAPProvider(ctx context.Context, req *mgmt_pb.AddLDAPProviderRequest) (*mgmt_pb.AddLDAPProviderResponse, error) {
|
||||
id, details, err := s.command.AddOrgLDAPProvider(ctx, authz.GetCtxData(ctx).OrgID, addLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.AddLDAPProviderResponse{
|
||||
Id: id,
|
||||
Details: object_pb.DomainToAddDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) UpdateLDAPProvider(ctx context.Context, req *mgmt_pb.UpdateLDAPProviderRequest) (*mgmt_pb.UpdateLDAPProviderResponse, error) {
|
||||
details, err := s.command.UpdateOrgLDAPProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id, updateLDAPProviderToCommand(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.UpdateLDAPProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) DeleteProvider(ctx context.Context, req *mgmt_pb.DeleteProviderRequest) (*mgmt_pb.DeleteProviderResponse, error) {
|
||||
details, err := s.command.DeleteOrgProvider(ctx, authz.GetCtxData(ctx).OrgID, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mgmt_pb.DeleteProviderResponse{
|
||||
Details: object_pb.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
idp_grpc "github.com/zitadel/zitadel/internal/api/grpc/idp"
|
||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
@ -170,3 +171,81 @@ func userLinksToDomain(idps []*query.IDPUserLink) []*domain.UserIDPLink {
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
func listProvidersToQuery(ctx context.Context, req *mgmt_pb.ListProvidersRequest) (*query.IDPTemplateSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||
queries, err := providerQueriesToQuery(req.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resourceOwnerQuery, err := query.NewIDPTemplateResourceOwnerListSearchQuery(authz.GetInstance(ctx).InstanceID(), authz.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queries = append(queries, resourceOwnerQuery)
|
||||
return &query.IDPTemplateSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func providerQueriesToQuery(queries []*mgmt_pb.ProviderQuery) (q []query.SearchQuery, err error) {
|
||||
q = make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = providerQueryToQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func providerQueryToQuery(idpQuery *mgmt_pb.ProviderQuery) (query.SearchQuery, error) {
|
||||
switch q := idpQuery.Query.(type) {
|
||||
case *mgmt_pb.ProviderQuery_IdpNameQuery:
|
||||
return query.NewIDPTemplateNameSearchQuery(object.TextMethodToQuery(q.IdpNameQuery.Method), q.IdpNameQuery.Name)
|
||||
case *mgmt_pb.ProviderQuery_IdpIdQuery:
|
||||
return query.NewIDPTemplateIDSearchQuery(q.IdpIdQuery.Id)
|
||||
case *mgmt_pb.ProviderQuery_OwnerTypeQuery:
|
||||
return query.NewIDPTemplateOwnerTypeSearchQuery(idp_grpc.IDPProviderTypeFromPb(q.OwnerTypeQuery.OwnerType))
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgument(nil, "ORG-Dr2aa", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func addLDAPProviderToCommand(req *mgmt_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateLDAPProviderToCommand(req *mgmt_pb.UpdateLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
17
internal/command/idp.go
Normal file
17
internal/command/idp.go
Normal file
@ -0,0 +1,17 @@
|
||||
package command
|
||||
|
||||
import "github.com/zitadel/zitadel/internal/repository/idp"
|
||||
|
||||
type LDAPProvider struct {
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password string
|
||||
LDAPAttributes idp.LDAPAttributes
|
||||
IDPOptions idp.Options
|
||||
}
|
208
internal/command/idp_model.go
Normal file
208
internal/command/idp_model.go
Normal file
@ -0,0 +1,208 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type LDAPIDPWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
idp.LDAPAttributes
|
||||
idp.Options
|
||||
|
||||
State domain.IDPState
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.reduceAddeddEvent(e)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.reduceChangedEvent(e)
|
||||
case *idp.RemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.IDPStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceAddeddEvent(e *idp.LDAPIDPAddedEvent) {
|
||||
wm.Name = e.Name
|
||||
wm.Host = e.Host
|
||||
wm.Port = e.Port
|
||||
wm.TLS = e.TLS
|
||||
wm.BaseDN = e.BaseDN
|
||||
wm.UserObjectClass = e.UserObjectClass
|
||||
wm.UserUniqueAttribute = e.UserUniqueAttribute
|
||||
wm.Admin = e.Admin
|
||||
wm.Password = e.Password
|
||||
wm.LDAPAttributes = e.LDAPAttributes
|
||||
wm.Options = e.Options
|
||||
wm.State = domain.IDPStateActive
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceChangedEvent(e *idp.LDAPIDPChangedEvent) {
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.Host != nil {
|
||||
wm.Host = *e.Host
|
||||
}
|
||||
if e.Port != nil {
|
||||
wm.Port = *e.Port
|
||||
}
|
||||
if e.TLS != nil {
|
||||
wm.TLS = *e.TLS
|
||||
}
|
||||
if e.BaseDN != nil {
|
||||
wm.BaseDN = *e.BaseDN
|
||||
}
|
||||
if e.UserObjectClass != nil {
|
||||
wm.UserObjectClass = *e.UserObjectClass
|
||||
}
|
||||
if e.UserUniqueAttribute != nil {
|
||||
wm.UserUniqueAttribute = *e.UserUniqueAttribute
|
||||
}
|
||||
if e.Admin != nil {
|
||||
wm.Admin = *e.Admin
|
||||
}
|
||||
if e.Password != nil {
|
||||
wm.Password = e.Password
|
||||
}
|
||||
wm.LDAPAttributes.ReduceChanges(e.LDAPAttributeChanges)
|
||||
wm.Options.ReduceChanges(e.OptionChanges)
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) NewChanges(
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) ([]idp.LDAPIDPChanges, error) {
|
||||
changes := make([]idp.LDAPIDPChanges, 0)
|
||||
var cryptedPassword *crypto.CryptoValue
|
||||
var err error
|
||||
if password != "" {
|
||||
cryptedPassword, err = crypto.Crypt([]byte(password), secretCrypto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes = append(changes, idp.ChangeLDAPPassword(cryptedPassword))
|
||||
}
|
||||
if wm.Name != name {
|
||||
changes = append(changes, idp.ChangeLDAPName(name))
|
||||
}
|
||||
if wm.Host != host {
|
||||
changes = append(changes, idp.ChangeLDAPHost(host))
|
||||
}
|
||||
if wm.Port != port {
|
||||
changes = append(changes, idp.ChangeLDAPPort(port))
|
||||
}
|
||||
if wm.TLS != tls {
|
||||
changes = append(changes, idp.ChangeLDAPTLS(tls))
|
||||
}
|
||||
if wm.BaseDN != baseDN {
|
||||
changes = append(changes, idp.ChangeLDAPBaseDN(baseDN))
|
||||
}
|
||||
if wm.UserObjectClass != userObjectClass {
|
||||
changes = append(changes, idp.ChangeLDAPUserObjectClass(userObjectClass))
|
||||
}
|
||||
if wm.UserUniqueAttribute != userUniqueAttribute {
|
||||
changes = append(changes, idp.ChangeLDAPUserUniqueAttribute(userUniqueAttribute))
|
||||
}
|
||||
if wm.Admin != admin {
|
||||
changes = append(changes, idp.ChangeLDAPAdmin(admin))
|
||||
}
|
||||
attrs := wm.LDAPAttributes.Changes(attributes)
|
||||
if !attrs.IsZero() {
|
||||
changes = append(changes, idp.ChangeLDAPAttributes(attrs))
|
||||
}
|
||||
opts := wm.Options.Changes(options)
|
||||
if !opts.IsZero() {
|
||||
changes = append(changes, idp.ChangeLDAPOptions(opts))
|
||||
}
|
||||
return changes, nil
|
||||
}
|
||||
|
||||
type IDPRemoveWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
State domain.IDPState
|
||||
name string
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *idp.LDAPIDPAddedEvent:
|
||||
wm.reduceAdded(e.ID, e.Name)
|
||||
case *idp.LDAPIDPChangedEvent:
|
||||
wm.reduceChanged(e.ID, e.Name)
|
||||
case *idp.RemovedEvent:
|
||||
wm.reduceRemoved(e.ID)
|
||||
case *idpconfig.IDPConfigAddedEvent:
|
||||
wm.reduceAdded(e.ConfigID, "")
|
||||
case *idpconfig.IDPConfigRemovedEvent:
|
||||
wm.reduceRemoved(e.ConfigID)
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceAdded(id string, name string) {
|
||||
if wm.ID != id {
|
||||
return
|
||||
}
|
||||
wm.State = domain.IDPStateActive
|
||||
wm.name = name
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceChanged(id string, name *string) {
|
||||
if wm.ID != id || name == nil {
|
||||
return
|
||||
}
|
||||
wm.name = *name
|
||||
}
|
||||
|
||||
func (wm *IDPRemoveWriteModel) reduceRemoved(id string) {
|
||||
if wm.ID != id {
|
||||
return
|
||||
}
|
||||
wm.State = domain.IDPStateRemoved
|
||||
}
|
205
internal/command/instance_idp.go
Normal file
205
internal/command/instance_idp.go
Normal file
@ -0,0 +1,205 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func (c *Commands) AddInstanceLDAPProvider(ctx context.Context, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddInstanceLDAPProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateInstanceLDAPProvider(ctx context.Context, id string, provider LDAPProvider) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateInstanceLDAPProvider(instanceAgg, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteInstanceProvider(ctx context.Context, id string) (*domain.ObjectDetails, error) {
|
||||
instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID())
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareDeleteInstanceProvider(instanceAgg, id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf5h", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
instance.NewLDAPIDPAddedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
secret,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateInstanceLDAPProvider(a *instance.Aggregate, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dgdbs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPInstanceIDPWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "INST-ASF3F", "Errors.Instance.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareDeleteInstanceProvider(a *instance.Aggregate, id string) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewInstanceIDPRemoveWriteModel(a.InstanceID, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "INST-Se3tg", "Errors.Instance.IDPConfig.NotExisting")
|
||||
}
|
||||
return []eventstore.Command{instance.NewIDPRemovedEvent(ctx, &a.Aggregate, id, writeModel.name)}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
163
internal/command/instance_idp_model.go
Normal file
163
internal/command/instance_idp_model.go
Normal file
@ -0,0 +1,163 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
type InstanceLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
|
||||
func NewLDAPInstanceIDPWriteModel(instanceID, id string) *InstanceLDAPIDPWriteModel {
|
||||
return &InstanceLDAPIDPWriteModel{
|
||||
LDAPIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) Reduce() error {
|
||||
return wm.LDAPIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *instance.IDPRemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.LDAPIDPWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.LDAPIDPAddedEventType,
|
||||
instance.LDAPIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) (*instance.LDAPIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := instance.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type InstanceIDPRemoveWriteModel struct {
|
||||
IDPRemoveWriteModel
|
||||
}
|
||||
|
||||
func NewInstanceIDPRemoveWriteModel(instanceID, id string) *InstanceIDPRemoveWriteModel {
|
||||
return &InstanceIDPRemoveWriteModel{
|
||||
IDPRemoveWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: instanceID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) Reduce() error {
|
||||
return wm.IDPRemoveWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *instance.IDPRemovedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *InstanceIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(instance.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
instance.LDAPIDPAddedEventType,
|
||||
instance.LDAPIDPChangedEventType,
|
||||
instance.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
684
internal/command/instance_idp_test.go
Normal file
684
internal/command/instance_idp_test.go
Normal file
@ -0,0 +1,684 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddInstanceLDAPProvider(tt.args.ctx, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
id string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusherWithInstanceID(
|
||||
"instance1",
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := instance.NewLDAPIDPChangedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
LastNameAttribute: stringPointer("new lastName"),
|
||||
DisplayNameAttribute: stringPointer("new displayName"),
|
||||
NickNameAttribute: stringPointer("new nickName"),
|
||||
PreferredUsernameAttribute: stringPointer("new preferredUsername"),
|
||||
EmailAttribute: stringPointer("new email"),
|
||||
EmailVerifiedAttribute: stringPointer("new emailVerified"),
|
||||
PhoneAttribute: stringPointer("new phone"),
|
||||
PhoneVerifiedAttribute: stringPointer("new phoneVerified"),
|
||||
PreferredLanguageAttribute: stringPointer("new preferredLanguage"),
|
||||
AvatarURLAttribute: stringPointer("new avatarURL"),
|
||||
ProfileAttribute: stringPointer("new profile"),
|
||||
}),
|
||||
idp.ChangeLDAPOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "instance1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
LastNameAttribute: "new lastName",
|
||||
DisplayNameAttribute: "new displayName",
|
||||
NickNameAttribute: "new nickName",
|
||||
PreferredUsernameAttribute: "new preferredUsername",
|
||||
EmailAttribute: "new email",
|
||||
EmailVerifiedAttribute: "new emailVerified",
|
||||
PhoneAttribute: "new phone",
|
||||
PhoneVerifiedAttribute: "new phoneVerified",
|
||||
PreferredLanguageAttribute: "new preferredLanguage",
|
||||
AvatarURLAttribute: "new avatarURL",
|
||||
ProfileAttribute: "new profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "instance1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateInstanceLDAPProvider(tt.args.ctx, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
204
internal/command/org_idp.go
Normal file
204
internal/command/org_idp.go
Normal file
@ -0,0 +1,204 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func (c *Commands) AddOrgLDAPProvider(ctx context.Context, resourceOwner string, provider LDAPProvider) (string, *domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
id, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareAddOrgLDAPProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return id, pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) UpdateOrgLDAPProvider(ctx context.Context, resourceOwner, id string, provider LDAPProvider) (*domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareUpdateOrgLDAPProvider(orgAgg, resourceOwner, id, provider))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cmds) == 0 {
|
||||
// no change, so return directly
|
||||
return &domain.ObjectDetails{}, nil
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) DeleteOrgProvider(ctx context.Context, resourceOwner, id string) (*domain.ObjectDetails, error) {
|
||||
orgAgg := org.NewAggregate(resourceOwner)
|
||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareDeleteOrgProvider(orgAgg, resourceOwner, id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pushedEvents, err := c.eventstore.Push(ctx, cmds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pushedEventsToObjectDetails(pushedEvents), nil
|
||||
}
|
||||
|
||||
func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, resourceOwner, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdf5h", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []eventstore.Command{
|
||||
org.NewLDAPIDPAddedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
secret,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareUpdateOrgLDAPProvider(a *org.Aggregate, resourceOwner, id string, provider LDAPProvider) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
if id = strings.TrimSpace(id); id == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dgdbs", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewLDAPOrgIDPWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-ASF3F", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
event, err := writeModel.NewChangedEvent(
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
id,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if event == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return []eventstore.Command{event}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Commands) prepareDeleteOrgProvider(a *org.Aggregate, resourceOwner, id string) preparation.Validation {
|
||||
return func() (preparation.CreateCommands, error) {
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
writeModel := NewOrgIDPRemoveWriteModel(resourceOwner, id)
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
writeModel.AppendEvents(events...)
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !writeModel.State.Exists() {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "ORG-Se3tg", "Errors.Org.IDPConfig.NotExisting")
|
||||
}
|
||||
return []eventstore.Command{org.NewIDPRemovedEvent(ctx, &a.Aggregate, id, writeModel.name)}, nil
|
||||
}, nil
|
||||
}
|
||||
}
|
163
internal/command/org_idp_model.go
Normal file
163
internal/command/org_idp_model.go
Normal file
@ -0,0 +1,163 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
type OrgLDAPIDPWriteModel struct {
|
||||
LDAPIDPWriteModel
|
||||
}
|
||||
|
||||
func NewLDAPOrgIDPWriteModel(orgID, id string) *OrgLDAPIDPWriteModel {
|
||||
return &OrgLDAPIDPWriteModel{
|
||||
LDAPIDPWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) Reduce() error {
|
||||
return wm.LDAPIDPWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *org.IDPRemovedEvent:
|
||||
if wm.ID != e.ID {
|
||||
continue
|
||||
}
|
||||
wm.LDAPIDPWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.LDAPIDPWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.LDAPIDPAddedEventType,
|
||||
org.LDAPIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) (*org.LDAPIDPChangedEvent, error) {
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
changeEvent, err := org.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type OrgIDPRemoveWriteModel struct {
|
||||
IDPRemoveWriteModel
|
||||
}
|
||||
|
||||
func NewOrgIDPRemoveWriteModel(orgID, id string) *OrgIDPRemoveWriteModel {
|
||||
return &OrgIDPRemoveWriteModel{
|
||||
IDPRemoveWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: orgID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
ID: id,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) Reduce() error {
|
||||
return wm.IDPRemoveWriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) AppendEvents(events ...eventstore.Event) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPAddedEvent)
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.LDAPIDPChangedEvent)
|
||||
case *org.IDPRemovedEvent:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
default:
|
||||
wm.IDPRemoveWriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OrgIDPRemoveWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(org.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(
|
||||
org.LDAPIDPAddedEventType,
|
||||
org.LDAPIDPChangedEventType,
|
||||
org.IDPRemovedEventType,
|
||||
).
|
||||
Builder()
|
||||
}
|
698
internal/command/org_idp_test.go
Normal file
698
internal/command/org_idp_test.go
Normal file
@ -0,0 +1,698 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errors "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok all set",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
LastNameAttribute: "lastName",
|
||||
DisplayNameAttribute: "displayName",
|
||||
NickNameAttribute: "nickName",
|
||||
PreferredUsernameAttribute: "preferredUsername",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "preferredLanguage",
|
||||
AvatarURLAttribute: "avatarURL",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
id: "id1",
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddOrgLDAPProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
secretCrypto crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
resourceOwner string
|
||||
id string
|
||||
provider LDAPProvider
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
"invalid id",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid name",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: caos_errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no changes",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
func() eventstore.Command {
|
||||
t := true
|
||||
event, _ := org.NewLDAPIDPChangedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
LastNameAttribute: stringPointer("new lastName"),
|
||||
DisplayNameAttribute: stringPointer("new displayName"),
|
||||
NickNameAttribute: stringPointer("new nickName"),
|
||||
PreferredUsernameAttribute: stringPointer("new preferredUsername"),
|
||||
EmailAttribute: stringPointer("new email"),
|
||||
EmailVerifiedAttribute: stringPointer("new emailVerified"),
|
||||
PhoneAttribute: stringPointer("new phone"),
|
||||
PhoneVerifiedAttribute: stringPointer("new phoneVerified"),
|
||||
PreferredLanguageAttribute: stringPointer("new preferredLanguage"),
|
||||
AvatarURLAttribute: stringPointer("new avatarURL"),
|
||||
ProfileAttribute: stringPointer("new profile"),
|
||||
}),
|
||||
idp.ChangeLDAPOptions(idp.OptionChanges{
|
||||
IsCreationAllowed: &t,
|
||||
IsLinkingAllowed: &t,
|
||||
IsAutoCreation: &t,
|
||||
IsAutoUpdate: &t,
|
||||
}),
|
||||
},
|
||||
)
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "org1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
LastNameAttribute: "new lastName",
|
||||
DisplayNameAttribute: "new displayName",
|
||||
NickNameAttribute: "new nickName",
|
||||
PreferredUsernameAttribute: "new preferredUsername",
|
||||
EmailAttribute: "new email",
|
||||
EmailVerifiedAttribute: "new emailVerified",
|
||||
PhoneAttribute: "new phone",
|
||||
PhoneVerifiedAttribute: "new phoneVerified",
|
||||
PreferredLanguageAttribute: "new preferredLanguage",
|
||||
AvatarURLAttribute: "new avatarURL",
|
||||
ProfileAttribute: "new profile",
|
||||
},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{ResourceOwner: "org1"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateOrgLDAPProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func stringPointer(s string) *string {
|
||||
return &s
|
||||
}
|
36
internal/domain/idp.go
Normal file
36
internal/domain/idp.go
Normal file
@ -0,0 +1,36 @@
|
||||
package domain
|
||||
|
||||
type IDPState int32
|
||||
|
||||
const (
|
||||
IDPStateUnspecified IDPState = iota
|
||||
IDPStateActive
|
||||
IDPStateInactive
|
||||
IDPStateRemoved
|
||||
|
||||
idpStateCount
|
||||
)
|
||||
|
||||
func (s IDPState) Valid() bool {
|
||||
return s >= 0 && s < idpStateCount
|
||||
}
|
||||
|
||||
func (s IDPState) Exists() bool {
|
||||
return s != IDPStateUnspecified && s != IDPStateRemoved
|
||||
}
|
||||
|
||||
type IDPType int32
|
||||
|
||||
const (
|
||||
IDPTypeUnspecified IDPType = iota
|
||||
IDPTypeOIDC
|
||||
IDPTypeJWT
|
||||
IDPTypeOAuth
|
||||
IDPTypeLDAP
|
||||
IDPTypeAzureAD
|
||||
IDPTypeGitHub
|
||||
IDPTypeGitHubEE
|
||||
IDPTypeGitLab
|
||||
IDPTypeGitLabSelfHosted
|
||||
IDPTypeGoogle
|
||||
)
|
237
internal/idp/providers/ldap/ldap.go
Normal file
237
internal/idp/providers/ldap/ldap.go
Normal file
@ -0,0 +1,237 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/idp"
|
||||
)
|
||||
|
||||
const DefaultPort = "389"
|
||||
|
||||
var _ idp.Provider = (*Provider)(nil)
|
||||
|
||||
// Provider is the [idp.Provider] implementation for a generic LDAP provider
|
||||
type Provider struct {
|
||||
name string
|
||||
host string
|
||||
port string
|
||||
tls bool
|
||||
baseDN string
|
||||
userObjectClass string
|
||||
userUniqueAttribute string
|
||||
admin string
|
||||
password string
|
||||
loginUrl string
|
||||
|
||||
isLinkingAllowed bool
|
||||
isCreationAllowed bool
|
||||
isAutoCreation bool
|
||||
isAutoUpdate bool
|
||||
|
||||
idAttribute string
|
||||
firstNameAttribute string
|
||||
lastNameAttribute string
|
||||
displayNameAttribute string
|
||||
nickNameAttribute string
|
||||
preferredUsernameAttribute string
|
||||
emailAttribute string
|
||||
emailVerifiedAttribute string
|
||||
phoneAttribute string
|
||||
phoneVerifiedAttribute string
|
||||
preferredLanguageAttribute string
|
||||
avatarURLAttribute string
|
||||
profileAttribute string
|
||||
}
|
||||
|
||||
type ProviderOpts func(provider *Provider)
|
||||
|
||||
// WithLinkingAllowed allows end users to link the federated user to an existing one.
|
||||
func WithLinkingAllowed() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.isLinkingAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCreationAllowed allows end users to create a new user using the federated information.
|
||||
func WithCreationAllowed() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.isCreationAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithAutoCreation enables that federated users are automatically created if not already existing.
|
||||
func WithAutoCreation() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.isAutoCreation = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithAutoUpdate enables that information retrieved from the provider is automatically used to update
|
||||
// the existing user on each authentication.
|
||||
func WithAutoUpdate() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.isAutoUpdate = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomPort configures a custom port used for the communication instead of :389 as per default
|
||||
func WithCustomPort(port string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.port = port
|
||||
}
|
||||
}
|
||||
|
||||
// Insecure configures to communication insecure with the LDAP server without TLS
|
||||
func Insecure() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.tls = false
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomIDAttribute configures to map the LDAP attribute to the user, default is the uniqueUserAttribute
|
||||
func WithCustomIDAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.idAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithFirstNameAttribute configures to map the LDAP attribute to the user
|
||||
func WithFirstNameAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.firstNameAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithLastNameAttribute configures to map the LDAP attribute to the user
|
||||
func WithLastNameAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.lastNameAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisplayNameAttribute configures to map the LDAP attribute to the user
|
||||
func WithDisplayNameAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.displayNameAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithNickNameAttribute configures to map the LDAP attribute to the user
|
||||
func WithNickNameAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.nickNameAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithPreferredUsernameAttribute configures to map the LDAP attribute to the user
|
||||
func WithPreferredUsernameAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.preferredUsernameAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithEmailAttribute configures to map the LDAP attribute to the user
|
||||
func WithEmailAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.emailAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithEmailVerifiedAttribute configures to map the LDAP attribute to the user
|
||||
func WithEmailVerifiedAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.emailVerifiedAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithPhoneAttribute configures to map the LDAP attribute to the user
|
||||
func WithPhoneAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.phoneAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithPhoneVerifiedAttribute configures to map the LDAP attribute to the user
|
||||
func WithPhoneVerifiedAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.phoneVerifiedAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithPreferredLanguageAttribute configures to map the LDAP attribute to the user
|
||||
func WithPreferredLanguageAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.preferredLanguageAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithAvatarURLAttribute configures to map the LDAP attribute to the user
|
||||
func WithAvatarURLAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.avatarURLAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
// WithProfileAttribute configures to map the LDAP attribute to the user
|
||||
func WithProfileAttribute(name string) ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.profileAttribute = name
|
||||
}
|
||||
}
|
||||
|
||||
func New(
|
||||
name string,
|
||||
host string,
|
||||
baseDN string,
|
||||
userObjectClass string,
|
||||
userUniqueAttribute string,
|
||||
admin string,
|
||||
password string,
|
||||
loginUrl string,
|
||||
options ...ProviderOpts,
|
||||
) *Provider {
|
||||
provider := &Provider{
|
||||
name: name,
|
||||
host: host,
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
baseDN: baseDN,
|
||||
userObjectClass: userObjectClass,
|
||||
userUniqueAttribute: userUniqueAttribute,
|
||||
admin: admin,
|
||||
password: password,
|
||||
loginUrl: loginUrl,
|
||||
idAttribute: userUniqueAttribute,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(provider)
|
||||
}
|
||||
return provider
|
||||
}
|
||||
|
||||
func (p *Provider) Name() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
func (p *Provider) BeginAuth(ctx context.Context, state string, params ...any) (idp.Session, error) {
|
||||
return &Session{
|
||||
Provider: p,
|
||||
loginUrl: p.loginUrl + "?state=" + state,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Provider) IsLinkingAllowed() bool {
|
||||
return p.isLinkingAllowed
|
||||
}
|
||||
|
||||
func (p *Provider) IsCreationAllowed() bool {
|
||||
return p.isCreationAllowed
|
||||
}
|
||||
|
||||
func (p *Provider) IsAutoCreation() bool {
|
||||
return p.isAutoCreation
|
||||
}
|
||||
|
||||
func (p *Provider) IsAutoUpdate() bool {
|
||||
return p.isAutoUpdate
|
||||
}
|
185
internal/idp/providers/ldap/ldap_test.go
Normal file
185
internal/idp/providers/ldap/ldap_test.go
Normal file
@ -0,0 +1,185 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestProvider_Options(t *testing.T) {
|
||||
type fields struct {
|
||||
name string
|
||||
host string
|
||||
baseDN string
|
||||
userObjectClass string
|
||||
userUniqueAttribute string
|
||||
admin string
|
||||
password string
|
||||
loginUrl string
|
||||
opts []ProviderOpts
|
||||
}
|
||||
type want struct {
|
||||
name string
|
||||
port string
|
||||
tls bool
|
||||
linkingAllowed bool
|
||||
creationAllowed bool
|
||||
autoCreation bool
|
||||
autoUpdate bool
|
||||
idAttribute string
|
||||
firstNameAttribute string
|
||||
lastNameAttribute string
|
||||
displayNameAttribute string
|
||||
nickNameAttribute string
|
||||
preferredUsernameAttribute string
|
||||
emailAttribute string
|
||||
emailVerifiedAttribute string
|
||||
phoneAttribute string
|
||||
phoneVerifiedAttribute string
|
||||
preferredLanguageAttribute string
|
||||
avatarURLAttribute string
|
||||
profileAttribute string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
opts: nil,
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
linkingAllowed: false,
|
||||
creationAllowed: false,
|
||||
autoCreation: false,
|
||||
autoUpdate: false,
|
||||
idAttribute: "attr",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all true",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
opts: []ProviderOpts{
|
||||
WithLinkingAllowed(),
|
||||
WithCreationAllowed(),
|
||||
WithAutoCreation(),
|
||||
WithAutoUpdate(),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
linkingAllowed: true,
|
||||
creationAllowed: true,
|
||||
autoCreation: true,
|
||||
autoUpdate: true,
|
||||
idAttribute: "attr",
|
||||
},
|
||||
}, {
|
||||
name: "all true, attributes set",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
opts: []ProviderOpts{
|
||||
Insecure(),
|
||||
WithCustomPort("port"),
|
||||
WithLinkingAllowed(),
|
||||
WithCreationAllowed(),
|
||||
WithAutoCreation(),
|
||||
WithAutoUpdate(),
|
||||
WithCustomIDAttribute("id"),
|
||||
WithFirstNameAttribute("first"),
|
||||
WithLastNameAttribute("last"),
|
||||
WithDisplayNameAttribute("display"),
|
||||
WithNickNameAttribute("nick"),
|
||||
WithPreferredUsernameAttribute("prefUser"),
|
||||
WithEmailAttribute("email"),
|
||||
WithEmailVerifiedAttribute("emailVerified"),
|
||||
WithPhoneAttribute("phone"),
|
||||
WithPhoneVerifiedAttribute("phoneVerified"),
|
||||
WithPreferredLanguageAttribute("prefLang"),
|
||||
WithAvatarURLAttribute("avatar"),
|
||||
WithProfileAttribute("profile"),
|
||||
},
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: "port",
|
||||
tls: false,
|
||||
linkingAllowed: true,
|
||||
creationAllowed: true,
|
||||
autoCreation: true,
|
||||
autoUpdate: true,
|
||||
idAttribute: "id",
|
||||
firstNameAttribute: "first",
|
||||
lastNameAttribute: "last",
|
||||
displayNameAttribute: "display",
|
||||
nickNameAttribute: "nick",
|
||||
preferredUsernameAttribute: "prefUser",
|
||||
emailAttribute: "email",
|
||||
emailVerifiedAttribute: "emailVerified",
|
||||
phoneAttribute: "phone",
|
||||
phoneVerifiedAttribute: "phoneVerified",
|
||||
preferredLanguageAttribute: "prefLang",
|
||||
avatarURLAttribute: "avatar",
|
||||
profileAttribute: "profile",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
provider := New(tt.fields.name, tt.fields.host, tt.fields.baseDN, tt.fields.userObjectClass, tt.fields.userUniqueAttribute, tt.fields.admin, tt.fields.password, tt.fields.loginUrl, tt.fields.opts...)
|
||||
|
||||
a.Equal(tt.want.name, provider.Name())
|
||||
a.Equal(tt.want.port, provider.port)
|
||||
a.Equal(tt.want.tls, provider.tls)
|
||||
a.Equal(tt.want.linkingAllowed, provider.IsLinkingAllowed())
|
||||
a.Equal(tt.want.creationAllowed, provider.IsCreationAllowed())
|
||||
a.Equal(tt.want.autoCreation, provider.IsAutoCreation())
|
||||
a.Equal(tt.want.autoUpdate, provider.IsAutoUpdate())
|
||||
|
||||
a.Equal(tt.want.idAttribute, provider.idAttribute)
|
||||
a.Equal(tt.want.firstNameAttribute, provider.firstNameAttribute)
|
||||
a.Equal(tt.want.lastNameAttribute, provider.lastNameAttribute)
|
||||
a.Equal(tt.want.displayNameAttribute, provider.displayNameAttribute)
|
||||
a.Equal(tt.want.nickNameAttribute, provider.nickNameAttribute)
|
||||
a.Equal(tt.want.preferredUsernameAttribute, provider.preferredUsernameAttribute)
|
||||
a.Equal(tt.want.emailAttribute, provider.emailAttribute)
|
||||
a.Equal(tt.want.emailVerifiedAttribute, provider.emailVerifiedAttribute)
|
||||
a.Equal(tt.want.phoneAttribute, provider.phoneAttribute)
|
||||
a.Equal(tt.want.phoneVerifiedAttribute, provider.phoneVerifiedAttribute)
|
||||
a.Equal(tt.want.preferredLanguageAttribute, provider.preferredLanguageAttribute)
|
||||
a.Equal(tt.want.avatarURLAttribute, provider.avatarURLAttribute)
|
||||
a.Equal(tt.want.profileAttribute, provider.profileAttribute)
|
||||
})
|
||||
}
|
||||
}
|
98
internal/idp/providers/ldap/session.go
Normal file
98
internal/idp/providers/ldap/session.go
Normal file
@ -0,0 +1,98 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/idp"
|
||||
)
|
||||
|
||||
var ErrNoSingleUser = errors.New("user does not exist or too many entries returned")
|
||||
|
||||
var _ idp.Session = (*Session)(nil)
|
||||
|
||||
type Session struct {
|
||||
Provider *Provider
|
||||
loginUrl string
|
||||
user string
|
||||
password string
|
||||
}
|
||||
|
||||
func (s *Session) GetAuthURL() string {
|
||||
return s.loginUrl
|
||||
}
|
||||
func (s *Session) FetchUser(_ context.Context) (idp.User, error) {
|
||||
l, err := ldap.DialURL("ldap://" + s.Provider.host + ":" + s.Provider.port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
if s.Provider.tls {
|
||||
err = l.StartTLS(&tls.Config{ServerName: s.Provider.host})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Bind as the admin to search for user
|
||||
err = l.Bind("cn="+s.Provider.admin+","+s.Provider.baseDN, s.Provider.password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Search for user with the unique attribute for the userDN
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
s.Provider.baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass="+s.Provider.userObjectClass+")("+s.Provider.userUniqueAttribute+"=%s))", ldap.EscapeFilter(s.user)),
|
||||
[]string{"dn"},
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil, ErrNoSingleUser
|
||||
}
|
||||
|
||||
user := sr.Entries[0]
|
||||
// Bind as the user to verify their password
|
||||
err = l.Bind(user.DN, s.password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
emailVerified, err := strconv.ParseBool(user.GetAttributeValue(s.Provider.emailVerifiedAttribute))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
phoneVerified, err := strconv.ParseBool(user.GetAttributeValue(s.Provider.phoneVerifiedAttribute))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewUser(
|
||||
user.GetAttributeValue(s.Provider.idAttribute),
|
||||
user.GetAttributeValue(s.Provider.firstNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.lastNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.displayNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.nickNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.preferredUsernameAttribute),
|
||||
user.GetAttributeValue(s.Provider.emailAttribute),
|
||||
emailVerified,
|
||||
user.GetAttributeValue(s.Provider.phoneAttribute),
|
||||
phoneVerified,
|
||||
language.Make(user.GetAttributeValue(s.Provider.preferredLanguageAttribute)),
|
||||
user.GetAttributeValue(s.Provider.avatarURLAttribute),
|
||||
user.GetAttributeValue(s.Provider.profileAttribute),
|
||||
), nil
|
||||
}
|
91
internal/idp/providers/ldap/user.go
Normal file
91
internal/idp/providers/ldap/user.go
Normal file
@ -0,0 +1,91 @@
|
||||
package ldap
|
||||
|
||||
import "golang.org/x/text/language"
|
||||
|
||||
type User struct {
|
||||
id string
|
||||
firstName string
|
||||
lastName string
|
||||
displayName string
|
||||
nickName string
|
||||
preferredUsername string
|
||||
email string
|
||||
emailVerified bool
|
||||
phone string
|
||||
phoneVerified bool
|
||||
preferredLanguage language.Tag
|
||||
avatarURL string
|
||||
profile string
|
||||
}
|
||||
|
||||
func NewUser(
|
||||
id string,
|
||||
firstName string,
|
||||
lastName string,
|
||||
displayName string,
|
||||
nickName string,
|
||||
preferredUsername string,
|
||||
email string,
|
||||
emailVerified bool,
|
||||
phone string,
|
||||
phoneVerified bool,
|
||||
preferredLanguage language.Tag,
|
||||
avatarURL string,
|
||||
profile string,
|
||||
) *User {
|
||||
return &User{
|
||||
id,
|
||||
firstName,
|
||||
lastName,
|
||||
displayName,
|
||||
nickName,
|
||||
preferredUsername,
|
||||
email,
|
||||
emailVerified,
|
||||
phone,
|
||||
phoneVerified,
|
||||
preferredLanguage,
|
||||
avatarURL,
|
||||
profile,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) GetID() string {
|
||||
return u.id
|
||||
}
|
||||
func (u *User) GetFirstName() string {
|
||||
return u.firstName
|
||||
}
|
||||
func (u *User) GetLastName() string {
|
||||
return u.lastName
|
||||
}
|
||||
func (u *User) GetDisplayName() string {
|
||||
return u.displayName
|
||||
}
|
||||
func (u *User) GetNickname() string {
|
||||
return u.nickName
|
||||
}
|
||||
func (u *User) GetPreferredUsername() string {
|
||||
return u.preferredUsername
|
||||
}
|
||||
func (u *User) GetEmail() string {
|
||||
return u.email
|
||||
}
|
||||
func (u *User) IsEmailVerified() bool {
|
||||
return u.emailVerified
|
||||
}
|
||||
func (u *User) GetPhone() string {
|
||||
return u.phone
|
||||
}
|
||||
func (u *User) IsPhoneVerified() bool {
|
||||
return u.phoneVerified
|
||||
}
|
||||
func (u *User) GetPreferredLanguage() language.Tag {
|
||||
return u.preferredLanguage
|
||||
}
|
||||
func (u *User) GetAvatarURL() string {
|
||||
return u.avatarURL
|
||||
}
|
||||
func (u *User) GetProfile() string {
|
||||
return u.profile
|
||||
}
|
621
internal/query/idp_template.go
Normal file
621
internal/query/idp_template.go
Normal file
@ -0,0 +1,621 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
errs "errors"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
)
|
||||
|
||||
type IDPTemplate struct {
|
||||
CreationDate time.Time
|
||||
ChangeDate time.Time
|
||||
Sequence uint64
|
||||
ResourceOwner string
|
||||
ID string
|
||||
State domain.IDPState
|
||||
Name string
|
||||
Type domain.IDPType
|
||||
OwnerType domain.IdentityProviderType
|
||||
IsCreationAllowed bool
|
||||
IsLinkingAllowed bool
|
||||
IsAutoCreation bool
|
||||
IsAutoUpdate bool
|
||||
*LDAPIDPTemplate
|
||||
}
|
||||
|
||||
type IDPTemplates struct {
|
||||
SearchResponse
|
||||
Templates []*IDPTemplate
|
||||
}
|
||||
|
||||
type LDAPIDPTemplate struct {
|
||||
IDPID string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
idp.LDAPAttributes
|
||||
idp.Options
|
||||
}
|
||||
|
||||
var (
|
||||
idpTemplateTable = table{
|
||||
name: projection.IDPTemplateTable,
|
||||
instanceIDCol: projection.IDPTemplateInstanceIDCol,
|
||||
}
|
||||
IDPTemplateIDCol = Column{
|
||||
name: projection.IDPTemplateIDCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateCreationDateCol = Column{
|
||||
name: projection.IDPTemplateCreationDateCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateChangeDateCol = Column{
|
||||
name: projection.IDPTemplateChangeDateCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateSequenceCol = Column{
|
||||
name: projection.IDPTemplateSequenceCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateResourceOwnerCol = Column{
|
||||
name: projection.IDPTemplateResourceOwnerCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateInstanceIDCol = Column{
|
||||
name: projection.IDPTemplateInstanceIDCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateStateCol = Column{
|
||||
name: projection.IDPTemplateStateCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateNameCol = Column{
|
||||
name: projection.IDPTemplateNameCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateOwnerTypeCol = Column{
|
||||
name: projection.IDPOwnerTypeCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateTypeCol = Column{
|
||||
name: projection.IDPTemplateTypeCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateOwnerRemovedCol = Column{
|
||||
name: projection.IDPTemplateOwnerRemovedCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateIsCreationAllowedCol = Column{
|
||||
name: projection.IDPTemplateIsCreationAllowedCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateIsLinkingAllowedCol = Column{
|
||||
name: projection.IDPTemplateIsLinkingAllowedCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateIsAutoCreationCol = Column{
|
||||
name: projection.IDPTemplateIsAutoCreationCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
IDPTemplateIsAutoUpdateCol = Column{
|
||||
name: projection.IDPTemplateIsAutoUpdateCol,
|
||||
table: idpTemplateTable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ldapIdpTemplateTable = table{
|
||||
name: projection.IDPTemplateLDAPTable,
|
||||
instanceIDCol: projection.IDPTemplateInstanceIDCol,
|
||||
}
|
||||
LDAPIDCol = Column{
|
||||
name: projection.LDAPIDCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPInstanceIDCol = Column{
|
||||
name: projection.LDAPInstanceIDCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPHostCol = Column{
|
||||
name: projection.LDAPHostCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPortCol = Column{
|
||||
name: projection.LDAPPortCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPTlsCol = Column{
|
||||
name: projection.LDAPTlsCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPBaseDNCol = Column{
|
||||
name: projection.LDAPBaseDNCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPUserObjectClassCol = Column{
|
||||
name: projection.LDAPUserObjectClassCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPUserUniqueAttributeCol = Column{
|
||||
name: projection.LDAPUserUniqueAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPAdminCol = Column{
|
||||
name: projection.LDAPAdminCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPasswordCol = Column{
|
||||
name: projection.LDAPPasswordCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPIDAttributeCol = Column{
|
||||
name: projection.LDAPIDAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPFirstNameAttributeCol = Column{
|
||||
name: projection.LDAPFirstNameAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPLastNameAttributeCol = Column{
|
||||
name: projection.LDAPLastNameAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPDisplayNameAttributeCol = Column{
|
||||
name: projection.LDAPDisplayNameAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPNickNameAttributeCol = Column{
|
||||
name: projection.LDAPNickNameAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPreferredUsernameAttributeCol = Column{
|
||||
name: projection.LDAPPreferredUsernameAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPEmailAttributeCol = Column{
|
||||
name: projection.LDAPEmailAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPEmailVerifiedAttributeCol = Column{
|
||||
name: projection.LDAPEmailVerifiedAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPhoneAttributeCol = Column{
|
||||
name: projection.LDAPPhoneAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPhoneVerifiedAttributeCol = Column{
|
||||
name: projection.LDAPPhoneVerifiedAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPreferredLanguageAttributeCol = Column{
|
||||
name: projection.LDAPPreferredLanguageAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPAvatarURLAttributeCol = Column{
|
||||
name: projection.LDAPAvatarURLAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPProfileAttributeCol = Column{
|
||||
name: projection.LDAPProfileAttributeCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
)
|
||||
|
||||
// IDPTemplateByIDAndResourceOwner searches for the requested id in the context of the resource owner and IAM
|
||||
func (q *Queries) IDPTemplateByIDAndResourceOwner(ctx context.Context, shouldTriggerBulk bool, id, resourceOwner string, withOwnerRemoved bool) (_ *IDPTemplate, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if shouldTriggerBulk {
|
||||
err := projection.IDPTemplateProjection.Trigger(ctx)
|
||||
logging.OnError(err).WithField("projection", idpTemplateTable.identifier()).Warn("could not trigger projection for query")
|
||||
}
|
||||
|
||||
eq := sq.Eq{
|
||||
IDPTemplateIDCol.identifier(): id,
|
||||
IDPTemplateInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
if !withOwnerRemoved {
|
||||
eq[IDPTemplateOwnerRemovedCol.identifier()] = false
|
||||
}
|
||||
where := sq.And{
|
||||
eq,
|
||||
sq.Or{
|
||||
sq.Eq{IDPTemplateResourceOwnerCol.identifier(): resourceOwner},
|
||||
sq.Eq{IDPTemplateResourceOwnerCol.identifier(): authz.GetInstance(ctx).InstanceID()},
|
||||
},
|
||||
}
|
||||
stmt, scan := prepareIDPTemplateByIDQuery()
|
||||
query, args, err := stmt.Where(where).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SFAew", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
row := q.client.QueryRowContext(ctx, query, args...)
|
||||
return scan(row)
|
||||
}
|
||||
|
||||
// IDPTemplates searches idp templates matching the query
|
||||
func (q *Queries) IDPTemplates(ctx context.Context, queries *IDPTemplateSearchQueries, withOwnerRemoved bool) (idps *IDPTemplates, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := prepareIDPTemplatesQuery()
|
||||
eq := sq.Eq{
|
||||
IDPTemplateInstanceIDCol.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
if !withOwnerRemoved {
|
||||
eq[IDPTemplateOwnerRemovedCol.identifier()] = false
|
||||
}
|
||||
stmt, args, err := queries.toQuery(query).Where(eq).ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInvalidArgument(err, "QUERY-SAF34", "Errors.Query.InvalidRequest")
|
||||
}
|
||||
|
||||
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-BDFrq", "Errors.Internal")
|
||||
}
|
||||
idps, err = scan(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idps.LatestSequence, err = q.latestSequence(ctx, idpTemplateTable)
|
||||
return idps, err
|
||||
}
|
||||
|
||||
type IDPTemplateSearchQueries struct {
|
||||
SearchRequest
|
||||
Queries []SearchQuery
|
||||
}
|
||||
|
||||
func NewIDPTemplateIDSearchQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(IDPTemplateIDCol, id, TextEquals)
|
||||
}
|
||||
|
||||
func NewIDPTemplateOwnerTypeSearchQuery(ownerType domain.IdentityProviderType) (SearchQuery, error) {
|
||||
return NewNumberQuery(IDPTemplateOwnerTypeCol, ownerType, NumberEquals)
|
||||
}
|
||||
|
||||
func NewIDPTemplateNameSearchQuery(method TextComparison, value string) (SearchQuery, error) {
|
||||
return NewTextQuery(IDPTemplateNameCol, value, method)
|
||||
}
|
||||
|
||||
func NewIDPTemplateResourceOwnerSearchQuery(value string) (SearchQuery, error) {
|
||||
return NewTextQuery(IDPTemplateResourceOwnerCol, value, TextEquals)
|
||||
}
|
||||
|
||||
func NewIDPTemplateResourceOwnerListSearchQuery(ids ...string) (SearchQuery, error) {
|
||||
list := make([]interface{}, len(ids))
|
||||
for i, value := range ids {
|
||||
list[i] = value
|
||||
}
|
||||
return NewListQuery(IDPTemplateResourceOwnerCol, list, ListIn)
|
||||
}
|
||||
|
||||
func (q *IDPTemplateSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||
query = q.SearchRequest.toQuery(query)
|
||||
for _, q := range q.Queries {
|
||||
query = q.toQuery(query)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func prepareIDPTemplateByIDQuery() (sq.SelectBuilder, func(*sql.Row) (*IDPTemplate, error)) {
|
||||
return sq.Select(
|
||||
IDPTemplateIDCol.identifier(),
|
||||
IDPTemplateResourceOwnerCol.identifier(),
|
||||
IDPTemplateCreationDateCol.identifier(),
|
||||
IDPTemplateChangeDateCol.identifier(),
|
||||
IDPTemplateSequenceCol.identifier(),
|
||||
IDPTemplateStateCol.identifier(),
|
||||
IDPTemplateNameCol.identifier(),
|
||||
IDPTemplateTypeCol.identifier(),
|
||||
IDPTemplateOwnerTypeCol.identifier(),
|
||||
IDPTemplateIsCreationAllowedCol.identifier(),
|
||||
IDPTemplateIsLinkingAllowedCol.identifier(),
|
||||
IDPTemplateIsAutoCreationCol.identifier(),
|
||||
IDPTemplateIsAutoUpdateCol.identifier(),
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
LDAPTlsCol.identifier(),
|
||||
LDAPBaseDNCol.identifier(),
|
||||
LDAPUserObjectClassCol.identifier(),
|
||||
LDAPUserUniqueAttributeCol.identifier(),
|
||||
LDAPAdminCol.identifier(),
|
||||
LDAPPasswordCol.identifier(),
|
||||
LDAPIDAttributeCol.identifier(),
|
||||
LDAPFirstNameAttributeCol.identifier(),
|
||||
LDAPLastNameAttributeCol.identifier(),
|
||||
LDAPDisplayNameAttributeCol.identifier(),
|
||||
LDAPNickNameAttributeCol.identifier(),
|
||||
LDAPPreferredUsernameAttributeCol.identifier(),
|
||||
LDAPEmailAttributeCol.identifier(),
|
||||
LDAPEmailVerifiedAttributeCol.identifier(),
|
||||
LDAPPhoneAttributeCol.identifier(),
|
||||
LDAPPhoneVerifiedAttributeCol.identifier(),
|
||||
LDAPPreferredLanguageAttributeCol.identifier(),
|
||||
LDAPAvatarURLAttributeCol.identifier(),
|
||||
LDAPProfileAttributeCol.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*IDPTemplate, error) {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
ldapTls := sql.NullBool{}
|
||||
ldapBaseDN := sql.NullString{}
|
||||
ldapUserObjectClass := sql.NullString{}
|
||||
ldapUserUniqueAttribute := sql.NullString{}
|
||||
ldapAdmin := sql.NullString{}
|
||||
ldapPassword := new(crypto.CryptoValue)
|
||||
ldapIDAttribute := sql.NullString{}
|
||||
ldapFirstNameAttribute := sql.NullString{}
|
||||
ldapLastNameAttribute := sql.NullString{}
|
||||
ldapDisplayNameAttribute := sql.NullString{}
|
||||
ldapNickNameAttribute := sql.NullString{}
|
||||
ldapPreferredUsernameAttribute := sql.NullString{}
|
||||
ldapEmailAttribute := sql.NullString{}
|
||||
ldapEmailVerifiedAttribute := sql.NullString{}
|
||||
ldapPhoneAttribute := sql.NullString{}
|
||||
ldapPhoneVerifiedAttribute := sql.NullString{}
|
||||
ldapPreferredLanguageAttribute := sql.NullString{}
|
||||
ldapAvatarURLAttribute := sql.NullString{}
|
||||
ldapProfileAttribute := sql.NullString{}
|
||||
|
||||
err := row.Scan(
|
||||
&idpTemplate.ID,
|
||||
&idpTemplate.ResourceOwner,
|
||||
&idpTemplate.CreationDate,
|
||||
&idpTemplate.ChangeDate,
|
||||
&idpTemplate.Sequence,
|
||||
&idpTemplate.State,
|
||||
&idpTemplate.Name,
|
||||
&idpTemplate.Type,
|
||||
&idpTemplate.OwnerType,
|
||||
&idpTemplate.IsCreationAllowed,
|
||||
&idpTemplate.IsLinkingAllowed,
|
||||
&idpTemplate.IsAutoCreation,
|
||||
&idpTemplate.IsAutoUpdate,
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
&ldapTls,
|
||||
&ldapBaseDN,
|
||||
&ldapUserObjectClass,
|
||||
&ldapUserUniqueAttribute,
|
||||
&ldapAdmin,
|
||||
&ldapPassword,
|
||||
&ldapIDAttribute,
|
||||
&ldapFirstNameAttribute,
|
||||
&ldapLastNameAttribute,
|
||||
&ldapDisplayNameAttribute,
|
||||
&ldapNickNameAttribute,
|
||||
&ldapPreferredUsernameAttribute,
|
||||
&ldapEmailAttribute,
|
||||
&ldapEmailVerifiedAttribute,
|
||||
&ldapPhoneAttribute,
|
||||
&ldapPhoneVerifiedAttribute,
|
||||
&ldapPreferredLanguageAttribute,
|
||||
&ldapAvatarURLAttribute,
|
||||
&ldapProfileAttribute,
|
||||
)
|
||||
if err != nil {
|
||||
if errs.Is(err, sql.ErrNoRows) {
|
||||
return nil, errors.ThrowNotFound(err, "QUERY-SAFrt", "Errors.IDPConfig.NotExisting")
|
||||
}
|
||||
return nil, errors.ThrowInternal(err, "QUERY-ADG42", "Errors.Internal")
|
||||
}
|
||||
|
||||
if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
Port: ldapPort.String,
|
||||
TLS: ldapTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
UserObjectClass: ldapUserObjectClass.String,
|
||||
UserUniqueAttribute: ldapUserUniqueAttribute.String,
|
||||
Admin: ldapAdmin.String,
|
||||
Password: ldapPassword,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: ldapIDAttribute.String,
|
||||
FirstNameAttribute: ldapFirstNameAttribute.String,
|
||||
LastNameAttribute: ldapLastNameAttribute.String,
|
||||
DisplayNameAttribute: ldapDisplayNameAttribute.String,
|
||||
NickNameAttribute: ldapNickNameAttribute.String,
|
||||
PreferredUsernameAttribute: ldapPreferredUsernameAttribute.String,
|
||||
EmailAttribute: ldapEmailAttribute.String,
|
||||
EmailVerifiedAttribute: ldapEmailVerifiedAttribute.String,
|
||||
PhoneAttribute: ldapPhoneAttribute.String,
|
||||
PhoneVerifiedAttribute: ldapPhoneVerifiedAttribute.String,
|
||||
PreferredLanguageAttribute: ldapPreferredLanguageAttribute.String,
|
||||
AvatarURLAttribute: ldapAvatarURLAttribute.String,
|
||||
ProfileAttribute: ldapProfileAttribute.String,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return idpTemplate, nil
|
||||
}
|
||||
}
|
||||
|
||||
func prepareIDPTemplatesQuery() (sq.SelectBuilder, func(*sql.Rows) (*IDPTemplates, error)) {
|
||||
return sq.Select(
|
||||
IDPTemplateIDCol.identifier(),
|
||||
IDPTemplateResourceOwnerCol.identifier(),
|
||||
IDPTemplateCreationDateCol.identifier(),
|
||||
IDPTemplateChangeDateCol.identifier(),
|
||||
IDPTemplateSequenceCol.identifier(),
|
||||
IDPTemplateStateCol.identifier(),
|
||||
IDPTemplateNameCol.identifier(),
|
||||
IDPTemplateTypeCol.identifier(),
|
||||
IDPTemplateOwnerTypeCol.identifier(),
|
||||
IDPTemplateIsCreationAllowedCol.identifier(),
|
||||
IDPTemplateIsLinkingAllowedCol.identifier(),
|
||||
IDPTemplateIsAutoCreationCol.identifier(),
|
||||
IDPTemplateIsAutoUpdateCol.identifier(),
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
LDAPTlsCol.identifier(),
|
||||
LDAPBaseDNCol.identifier(),
|
||||
LDAPUserObjectClassCol.identifier(),
|
||||
LDAPUserUniqueAttributeCol.identifier(),
|
||||
LDAPAdminCol.identifier(),
|
||||
LDAPPasswordCol.identifier(),
|
||||
LDAPIDAttributeCol.identifier(),
|
||||
LDAPFirstNameAttributeCol.identifier(),
|
||||
LDAPLastNameAttributeCol.identifier(),
|
||||
LDAPDisplayNameAttributeCol.identifier(),
|
||||
LDAPNickNameAttributeCol.identifier(),
|
||||
LDAPPreferredUsernameAttributeCol.identifier(),
|
||||
LDAPEmailAttributeCol.identifier(),
|
||||
LDAPEmailVerifiedAttributeCol.identifier(),
|
||||
LDAPPhoneAttributeCol.identifier(),
|
||||
LDAPPhoneVerifiedAttributeCol.identifier(),
|
||||
LDAPPreferredLanguageAttributeCol.identifier(),
|
||||
LDAPAvatarURLAttributeCol.identifier(),
|
||||
LDAPProfileAttributeCol.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(idpTemplateTable.identifier()).
|
||||
LeftJoin(join(LDAPIDCol, IDPTemplateIDCol)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*IDPTemplates, error) {
|
||||
templates := make([]*IDPTemplate, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
idpTemplate := new(IDPTemplate)
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
ldapTls := sql.NullBool{}
|
||||
ldapBaseDN := sql.NullString{}
|
||||
ldapUserObjectClass := sql.NullString{}
|
||||
ldapUserUniqueAttribute := sql.NullString{}
|
||||
ldapAdmin := sql.NullString{}
|
||||
ldapPassword := new(crypto.CryptoValue)
|
||||
ldapIDAttribute := sql.NullString{}
|
||||
ldapFirstNameAttribute := sql.NullString{}
|
||||
ldapLastNameAttribute := sql.NullString{}
|
||||
ldapDisplayNameAttribute := sql.NullString{}
|
||||
ldapNickNameAttribute := sql.NullString{}
|
||||
ldapPreferredUsernameAttribute := sql.NullString{}
|
||||
ldapEmailAttribute := sql.NullString{}
|
||||
ldapEmailVerifiedAttribute := sql.NullString{}
|
||||
ldapPhoneAttribute := sql.NullString{}
|
||||
ldapPhoneVerifiedAttribute := sql.NullString{}
|
||||
ldapPreferredLanguageAttribute := sql.NullString{}
|
||||
ldapAvatarURLAttribute := sql.NullString{}
|
||||
ldapProfileAttribute := sql.NullString{}
|
||||
|
||||
err := rows.Scan(
|
||||
&idpTemplate.ID,
|
||||
&idpTemplate.ResourceOwner,
|
||||
&idpTemplate.CreationDate,
|
||||
&idpTemplate.ChangeDate,
|
||||
&idpTemplate.Sequence,
|
||||
&idpTemplate.State,
|
||||
&idpTemplate.Name,
|
||||
&idpTemplate.Type,
|
||||
&idpTemplate.OwnerType,
|
||||
&idpTemplate.IsCreationAllowed,
|
||||
&idpTemplate.IsLinkingAllowed,
|
||||
&idpTemplate.IsAutoCreation,
|
||||
&idpTemplate.IsAutoUpdate,
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
&ldapTls,
|
||||
&ldapBaseDN,
|
||||
&ldapUserObjectClass,
|
||||
&ldapUserUniqueAttribute,
|
||||
&ldapAdmin,
|
||||
&ldapPassword,
|
||||
&ldapIDAttribute,
|
||||
&ldapFirstNameAttribute,
|
||||
&ldapLastNameAttribute,
|
||||
&ldapDisplayNameAttribute,
|
||||
&ldapNickNameAttribute,
|
||||
&ldapPreferredUsernameAttribute,
|
||||
&ldapEmailAttribute,
|
||||
&ldapEmailVerifiedAttribute,
|
||||
&ldapPhoneAttribute,
|
||||
&ldapPhoneVerifiedAttribute,
|
||||
&ldapPreferredLanguageAttribute,
|
||||
&ldapAvatarURLAttribute,
|
||||
&ldapProfileAttribute,
|
||||
&count,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
Port: ldapPort.String,
|
||||
TLS: ldapTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
UserObjectClass: ldapUserObjectClass.String,
|
||||
UserUniqueAttribute: ldapUserUniqueAttribute.String,
|
||||
Admin: ldapAdmin.String,
|
||||
Password: ldapPassword,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: ldapIDAttribute.String,
|
||||
FirstNameAttribute: ldapFirstNameAttribute.String,
|
||||
LastNameAttribute: ldapLastNameAttribute.String,
|
||||
DisplayNameAttribute: ldapDisplayNameAttribute.String,
|
||||
NickNameAttribute: ldapNickNameAttribute.String,
|
||||
PreferredUsernameAttribute: ldapPreferredUsernameAttribute.String,
|
||||
EmailAttribute: ldapEmailAttribute.String,
|
||||
EmailVerifiedAttribute: ldapEmailVerifiedAttribute.String,
|
||||
PhoneAttribute: ldapPhoneAttribute.String,
|
||||
PhoneVerifiedAttribute: ldapPhoneVerifiedAttribute.String,
|
||||
PreferredLanguageAttribute: ldapPreferredLanguageAttribute.String,
|
||||
AvatarURLAttribute: ldapAvatarURLAttribute.String,
|
||||
ProfileAttribute: ldapProfileAttribute.String,
|
||||
},
|
||||
}
|
||||
}
|
||||
templates = append(templates, idpTemplate)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, errors.ThrowInternal(err, "QUERY-SAGrt", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &IDPTemplates{
|
||||
Templates: templates,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
727
internal/query/idp_template_test.go
Normal file
727
internal/query/idp_template_test.go
Normal file
@ -0,0 +1,727 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
)
|
||||
|
||||
var (
|
||||
idpTemplateQuery = `SELECT projections.idp_templates.id,` +
|
||||
` projections.idp_templates.resource_owner,` +
|
||||
` projections.idp_templates.creation_date,` +
|
||||
` projections.idp_templates.change_date,` +
|
||||
` projections.idp_templates.sequence,` +
|
||||
` projections.idp_templates.state,` +
|
||||
` projections.idp_templates.name,` +
|
||||
` projections.idp_templates.type,` +
|
||||
` projections.idp_templates.owner_type,` +
|
||||
` projections.idp_templates.is_creation_allowed,` +
|
||||
` projections.idp_templates.is_linking_allowed,` +
|
||||
` projections.idp_templates.is_auto_creation,` +
|
||||
` projections.idp_templates.is_auto_update,` +
|
||||
` projections.idp_templates_ldap.idp_id,` +
|
||||
` projections.idp_templates_ldap.host,` +
|
||||
` projections.idp_templates_ldap.port,` +
|
||||
` projections.idp_templates_ldap.tls,` +
|
||||
` projections.idp_templates_ldap.base_dn,` +
|
||||
` projections.idp_templates_ldap.user_object_class,` +
|
||||
` projections.idp_templates_ldap.user_unique_attribute,` +
|
||||
` projections.idp_templates_ldap.admin,` +
|
||||
` projections.idp_templates_ldap.password,` +
|
||||
` projections.idp_templates_ldap.id_attribute,` +
|
||||
` projections.idp_templates_ldap.first_name_attribute,` +
|
||||
` projections.idp_templates_ldap.last_name_attribute,` +
|
||||
` projections.idp_templates_ldap.display_name_attribute,` +
|
||||
` projections.idp_templates_ldap.nick_name_attribute,` +
|
||||
` projections.idp_templates_ldap.preferred_username_attribute,` +
|
||||
` projections.idp_templates_ldap.email_attribute,` +
|
||||
` projections.idp_templates_ldap.email_verified,` +
|
||||
` projections.idp_templates_ldap.phone_attribute,` +
|
||||
` projections.idp_templates_ldap.phone_verified_attribute,` +
|
||||
` projections.idp_templates_ldap.preferred_language_attribute,` +
|
||||
` projections.idp_templates_ldap.avatar_url_attribute,` +
|
||||
` projections.idp_templates_ldap.profile_attribute` +
|
||||
` FROM projections.idp_templates` +
|
||||
` LEFT JOIN projections.idp_templates_ldap ON projections.idp_templates.id = projections.idp_templates_ldap.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_ldap.instance_id`
|
||||
idpTemplateCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"state",
|
||||
"name",
|
||||
"type",
|
||||
"owner_type",
|
||||
"is_creation_allowed",
|
||||
"is_linking_allowed",
|
||||
"is_auto_creation",
|
||||
"is_auto_update",
|
||||
// ldap config
|
||||
"idp_id",
|
||||
"host",
|
||||
"port",
|
||||
"tls",
|
||||
"base_dn",
|
||||
"user_object_class",
|
||||
"user_unique_attribute",
|
||||
"admin",
|
||||
"password",
|
||||
"id_attribute",
|
||||
"first_name_attribute",
|
||||
"last_name_attribute",
|
||||
"display_name_attribute",
|
||||
"nick_name_attribute",
|
||||
"preferred_username_attribute",
|
||||
"email_attribute",
|
||||
"email_verified",
|
||||
"phone_attribute",
|
||||
"phone_verified_attribute",
|
||||
"preferred_language_attribute",
|
||||
"avatar_url_attribute",
|
||||
"profile_attribute",
|
||||
}
|
||||
idpTemplatesQuery = `SELECT projections.idp_templates.id,` +
|
||||
` projections.idp_templates.resource_owner,` +
|
||||
` projections.idp_templates.creation_date,` +
|
||||
` projections.idp_templates.change_date,` +
|
||||
` projections.idp_templates.sequence,` +
|
||||
` projections.idp_templates.state,` +
|
||||
` projections.idp_templates.name,` +
|
||||
` projections.idp_templates.type,` +
|
||||
` projections.idp_templates.owner_type,` +
|
||||
` projections.idp_templates.is_creation_allowed,` +
|
||||
` projections.idp_templates.is_linking_allowed,` +
|
||||
` projections.idp_templates.is_auto_creation,` +
|
||||
` projections.idp_templates.is_auto_update,` +
|
||||
` projections.idp_templates_ldap.idp_id,` +
|
||||
` projections.idp_templates_ldap.host,` +
|
||||
` projections.idp_templates_ldap.port,` +
|
||||
` projections.idp_templates_ldap.tls,` +
|
||||
` projections.idp_templates_ldap.base_dn,` +
|
||||
` projections.idp_templates_ldap.user_object_class,` +
|
||||
` projections.idp_templates_ldap.user_unique_attribute,` +
|
||||
` projections.idp_templates_ldap.admin,` +
|
||||
` projections.idp_templates_ldap.password,` +
|
||||
` projections.idp_templates_ldap.id_attribute,` +
|
||||
` projections.idp_templates_ldap.first_name_attribute,` +
|
||||
` projections.idp_templates_ldap.last_name_attribute,` +
|
||||
` projections.idp_templates_ldap.display_name_attribute,` +
|
||||
` projections.idp_templates_ldap.nick_name_attribute,` +
|
||||
` projections.idp_templates_ldap.preferred_username_attribute,` +
|
||||
` projections.idp_templates_ldap.email_attribute,` +
|
||||
` projections.idp_templates_ldap.email_verified,` +
|
||||
` projections.idp_templates_ldap.phone_attribute,` +
|
||||
` projections.idp_templates_ldap.phone_verified_attribute,` +
|
||||
` projections.idp_templates_ldap.preferred_language_attribute,` +
|
||||
` projections.idp_templates_ldap.avatar_url_attribute,` +
|
||||
` projections.idp_templates_ldap.profile_attribute,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_templates` +
|
||||
` LEFT JOIN projections.idp_templates_ldap ON projections.idp_templates.id = projections.idp_templates_ldap.idp_id AND projections.idp_templates.instance_id = projections.idp_templates_ldap.instance_id`
|
||||
idpTemplatesCols = []string{
|
||||
"id",
|
||||
"resource_owner",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"state",
|
||||
"name",
|
||||
"type",
|
||||
"owner_type",
|
||||
"is_creation_allowed",
|
||||
"is_linking_allowed",
|
||||
"is_auto_creation",
|
||||
"is_auto_update",
|
||||
"idp_id",
|
||||
"host",
|
||||
"port",
|
||||
"tls",
|
||||
"base_dn",
|
||||
"user_object_class",
|
||||
"user_unique_attribute",
|
||||
"admin",
|
||||
"password",
|
||||
"id_attribute",
|
||||
"first_name_attribute",
|
||||
"last_name_attribute",
|
||||
"display_name_attribute",
|
||||
"nick_name_attribute",
|
||||
"preferred_username_attribute",
|
||||
"email_attribute",
|
||||
"email_verified",
|
||||
"phone_attribute",
|
||||
"phone_verified_attribute",
|
||||
"preferred_language_attribute",
|
||||
"avatar_url_attribute",
|
||||
"profile_attribute",
|
||||
"count",
|
||||
}
|
||||
)
|
||||
|
||||
func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
err checkErr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare interface{}
|
||||
want want
|
||||
object interface{}
|
||||
}{
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery no result",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errs.IsNotFound(err) {
|
||||
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: (*IDPTemplate)(nil),
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery ldap idp",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
idpTemplateCols,
|
||||
[]driver.Value{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
nil,
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"emailVerified",
|
||||
"phone",
|
||||
"phoneVerified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplate{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
LastNameAttribute: "last",
|
||||
DisplayNameAttribute: "display",
|
||||
NickNameAttribute: "nickname",
|
||||
PreferredUsernameAttribute: "username",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "lang",
|
||||
AvatarURLAttribute: "avatar",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery no config",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQuery(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
idpTemplateCols,
|
||||
[]driver.Value{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplate{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplateByIDQuery sql err",
|
||||
prepare: prepareIDPTemplateByIDQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(idpTemplateQuery),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errors.Is(err, sql.ErrConnDone) {
|
||||
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: nil,
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplatesQuery no result",
|
||||
prepare: prepareIDPTemplatesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(idpTemplatesQuery),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errs.IsNotFound(err) {
|
||||
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: &IDPTemplates{Templates: []*IDPTemplate{}},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplatesQuery ldap idp",
|
||||
prepare: prepareIDPTemplatesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(idpTemplatesQuery),
|
||||
idpTemplatesCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
nil,
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"emailVerified",
|
||||
"phone",
|
||||
"phoneVerified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplates{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Templates: []*IDPTemplate{
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
LastNameAttribute: "last",
|
||||
DisplayNameAttribute: "display",
|
||||
NickNameAttribute: "nickname",
|
||||
PreferredUsernameAttribute: "username",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "lang",
|
||||
AvatarURLAttribute: "avatar",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplatesQuery no config",
|
||||
prepare: prepareIDPTemplatesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(idpTemplatesQuery),
|
||||
idpTemplatesCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"idp-id",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplates{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Templates: []*IDPTemplate{
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplatesQuery all config types",
|
||||
prepare: prepareIDPTemplatesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(idpTemplatesQuery),
|
||||
idpTemplatesCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"idp-id-1",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
nil,
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"emailVerified",
|
||||
"phone",
|
||||
"phoneVerified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
},
|
||||
{
|
||||
"idp-id-2",
|
||||
"ro",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
domain.IDPConfigStateActive,
|
||||
"idp-name",
|
||||
domain.IDPTypeLDAP,
|
||||
domain.IdentityProviderTypeOrg,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
// ldap config
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &IDPTemplates{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 2,
|
||||
},
|
||||
Templates: []*IDPTemplate{
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id-1",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
LastNameAttribute: "last",
|
||||
DisplayNameAttribute: "display",
|
||||
NickNameAttribute: "nickname",
|
||||
PreferredUsernameAttribute: "username",
|
||||
EmailAttribute: "email",
|
||||
EmailVerifiedAttribute: "emailVerified",
|
||||
PhoneAttribute: "phone",
|
||||
PhoneVerifiedAttribute: "phoneVerified",
|
||||
PreferredLanguageAttribute: "lang",
|
||||
AvatarURLAttribute: "avatar",
|
||||
ProfileAttribute: "profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
Sequence: 20211109,
|
||||
ResourceOwner: "ro",
|
||||
ID: "idp-id-2",
|
||||
State: domain.IDPStateActive,
|
||||
Name: "idp-name",
|
||||
Type: domain.IDPTypeLDAP,
|
||||
OwnerType: domain.IdentityProviderTypeOrg,
|
||||
IsCreationAllowed: true,
|
||||
IsLinkingAllowed: true,
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepareIDPTemplatesQuery sql err",
|
||||
prepare: prepareIDPTemplatesQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(idpTemplatesQuery),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errors.Is(err, sql.ErrConnDone) {
|
||||
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
})
|
||||
}
|
||||
}
|
412
internal/query/projection/idp_template.go
Normal file
412
internal/query/projection/idp_template.go
Normal file
@ -0,0 +1,412 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/crdb"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
const (
|
||||
IDPTemplateTable = "projections.idp_templates"
|
||||
IDPTemplateLDAPTable = IDPTemplateTable + "_" + IDPTemplateLDAPSuffix
|
||||
|
||||
IDPTemplateLDAPSuffix = "ldap"
|
||||
|
||||
IDPTemplateIDCol = "id"
|
||||
IDPTemplateCreationDateCol = "creation_date"
|
||||
IDPTemplateChangeDateCol = "change_date"
|
||||
IDPTemplateSequenceCol = "sequence"
|
||||
IDPTemplateResourceOwnerCol = "resource_owner"
|
||||
IDPTemplateInstanceIDCol = "instance_id"
|
||||
IDPTemplateStateCol = "state"
|
||||
IDPTemplateNameCol = "name"
|
||||
IDPTemplateOwnerTypeCol = "owner_type"
|
||||
IDPTemplateTypeCol = "type"
|
||||
IDPTemplateOwnerRemovedCol = "owner_removed"
|
||||
IDPTemplateIsCreationAllowedCol = "is_creation_allowed"
|
||||
IDPTemplateIsLinkingAllowedCol = "is_linking_allowed"
|
||||
IDPTemplateIsAutoCreationCol = "is_auto_creation"
|
||||
IDPTemplateIsAutoUpdateCol = "is_auto_update"
|
||||
|
||||
LDAPIDCol = "idp_id"
|
||||
LDAPInstanceIDCol = "instance_id"
|
||||
LDAPHostCol = "host"
|
||||
LDAPPortCol = "port"
|
||||
LDAPTlsCol = "tls"
|
||||
LDAPBaseDNCol = "base_dn"
|
||||
LDAPUserObjectClassCol = "user_object_class"
|
||||
LDAPUserUniqueAttributeCol = "user_unique_attribute"
|
||||
LDAPAdminCol = "admin"
|
||||
LDAPPasswordCol = "password"
|
||||
LDAPIDAttributeCol = "id_attribute"
|
||||
LDAPFirstNameAttributeCol = "first_name_attribute"
|
||||
LDAPLastNameAttributeCol = "last_name_attribute"
|
||||
LDAPDisplayNameAttributeCol = "display_name_attribute"
|
||||
LDAPNickNameAttributeCol = "nick_name_attribute"
|
||||
LDAPPreferredUsernameAttributeCol = "preferred_username_attribute"
|
||||
LDAPEmailAttributeCol = "email_attribute"
|
||||
LDAPEmailVerifiedAttributeCol = "email_verified"
|
||||
LDAPPhoneAttributeCol = "phone_attribute"
|
||||
LDAPPhoneVerifiedAttributeCol = "phone_verified_attribute"
|
||||
LDAPPreferredLanguageAttributeCol = "preferred_language_attribute"
|
||||
LDAPAvatarURLAttributeCol = "avatar_url_attribute"
|
||||
LDAPProfileAttributeCol = "profile_attribute"
|
||||
)
|
||||
|
||||
type idpTemplateProjection struct {
|
||||
crdb.StatementHandler
|
||||
}
|
||||
|
||||
func newIDPTemplateProjection(ctx context.Context, config crdb.StatementHandlerConfig) *idpTemplateProjection {
|
||||
p := new(idpTemplateProjection)
|
||||
config.ProjectionName = IDPTemplateTable
|
||||
config.Reducers = p.reducers()
|
||||
config.InitCheck = crdb.NewMultiTableCheck(
|
||||
crdb.NewTable([]*crdb.Column{
|
||||
crdb.NewColumn(IDPTemplateIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(IDPTemplateCreationDateCol, crdb.ColumnTypeTimestamp),
|
||||
crdb.NewColumn(IDPTemplateChangeDateCol, crdb.ColumnTypeTimestamp),
|
||||
crdb.NewColumn(IDPTemplateSequenceCol, crdb.ColumnTypeInt64),
|
||||
crdb.NewColumn(IDPTemplateResourceOwnerCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(IDPTemplateInstanceIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(IDPTemplateStateCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPTemplateNameCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(IDPTemplateOwnerTypeCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPTemplateTypeCol, crdb.ColumnTypeEnum),
|
||||
crdb.NewColumn(IDPTemplateOwnerRemovedCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
crdb.NewColumn(IDPTemplateIsCreationAllowedCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
crdb.NewColumn(IDPTemplateIsLinkingAllowedCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
crdb.NewColumn(IDPTemplateIsAutoCreationCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
crdb.NewColumn(IDPTemplateIsAutoUpdateCol, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||
},
|
||||
crdb.NewPrimaryKey(IDPTemplateInstanceIDCol, IDPTemplateIDCol),
|
||||
crdb.WithIndex(crdb.NewIndex("resource_owner", []string{IDPTemplateResourceOwnerCol})),
|
||||
crdb.WithIndex(crdb.NewIndex("owner_removed", []string{IDPTemplateOwnerRemovedCol})),
|
||||
),
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(LDAPIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPInstanceIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPHostCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPortCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPTlsCol, crdb.ColumnTypeBool, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPBaseDNCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPUserObjectClassCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPUserUniqueAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPAdminCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPasswordCol, crdb.ColumnTypeJSONB, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPIDAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPFirstNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPLastNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPDisplayNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPNickNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPreferredUsernameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPEmailAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPEmailVerifiedAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPhoneAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPhoneVerifiedAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPreferredLanguageAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPAvatarURLAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPProfileAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
},
|
||||
crdb.NewPrimaryKey(LDAPInstanceIDCol, LDAPIDCol),
|
||||
IDPTemplateLDAPSuffix,
|
||||
crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys()),
|
||||
),
|
||||
)
|
||||
p.StatementHandler = crdb.NewStatementHandler(ctx, config)
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventRedusers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.LDAPIDPAddedEventType,
|
||||
Reduce: p.reduceLDAPIDPAdded,
|
||||
},
|
||||
{
|
||||
Event: instance.LDAPIDPChangedEventType,
|
||||
Reduce: p.reduceLDAPIDPChanged,
|
||||
},
|
||||
{
|
||||
Event: instance.IDPRemovedEventType,
|
||||
Reduce: p.reduceIDPRemoved,
|
||||
},
|
||||
{
|
||||
Event: instance.InstanceRemovedEventType,
|
||||
Reduce: reduceInstanceRemovedHelper(IDPTemplateInstanceIDCol),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventRedusers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.LDAPIDPAddedEventType,
|
||||
Reduce: p.reduceLDAPIDPAdded,
|
||||
},
|
||||
{
|
||||
Event: org.LDAPIDPChangedEventType,
|
||||
Reduce: p.reduceLDAPIDPChanged,
|
||||
},
|
||||
{
|
||||
Event: org.IDPRemovedEventType,
|
||||
Reduce: p.reduceIDPRemoved,
|
||||
},
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: p.reduceOwnerRemoved,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceLDAPIDPAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.LDAPIDPAddedEvent
|
||||
var idpOwnerType domain.IdentityProviderType
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPAddedEvent:
|
||||
idpEvent = e.LDAPIDPAddedEvent
|
||||
idpOwnerType = domain.IdentityProviderTypeOrg
|
||||
case *instance.LDAPIDPAddedEvent:
|
||||
idpEvent = e.LDAPIDPAddedEvent
|
||||
idpOwnerType = domain.IdentityProviderTypeSystem
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-9s02m1", "reduce.wrong.event.type %v", []eventstore.EventType{org.LDAPIDPAddedEventType, instance.LDAPIDPAddedEventType})
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(
|
||||
&idpEvent,
|
||||
crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCol(IDPTemplateCreationDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
|
||||
handler.NewCol(IDPTemplateResourceOwnerCol, idpEvent.Aggregate().ResourceOwner),
|
||||
handler.NewCol(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
handler.NewCol(IDPTemplateStateCol, domain.IDPStateActive),
|
||||
handler.NewCol(IDPTemplateNameCol, idpEvent.Name),
|
||||
handler.NewCol(IDPTemplateOwnerTypeCol, idpOwnerType),
|
||||
handler.NewCol(IDPTemplateTypeCol, domain.IDPTypeLDAP),
|
||||
handler.NewCol(IDPTemplateIsCreationAllowedCol, idpEvent.IsCreationAllowed),
|
||||
handler.NewCol(IDPTemplateIsLinkingAllowedCol, idpEvent.IsLinkingAllowed),
|
||||
handler.NewCol(IDPTemplateIsAutoCreationCol, idpEvent.IsAutoCreation),
|
||||
handler.NewCol(IDPTemplateIsAutoUpdateCol, idpEvent.IsAutoUpdate),
|
||||
},
|
||||
),
|
||||
crdb.AddCreateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(LDAPIDCol, idpEvent.ID),
|
||||
handler.NewCol(LDAPInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
handler.NewCol(LDAPHostCol, idpEvent.Host),
|
||||
handler.NewCol(LDAPPortCol, idpEvent.Port),
|
||||
handler.NewCol(LDAPTlsCol, idpEvent.TLS),
|
||||
handler.NewCol(LDAPBaseDNCol, idpEvent.BaseDN),
|
||||
handler.NewCol(LDAPUserObjectClassCol, idpEvent.UserObjectClass),
|
||||
handler.NewCol(LDAPUserUniqueAttributeCol, idpEvent.UserUniqueAttribute),
|
||||
handler.NewCol(LDAPAdminCol, idpEvent.Admin),
|
||||
handler.NewCol(LDAPPasswordCol, idpEvent.Password),
|
||||
handler.NewCol(LDAPIDAttributeCol, idpEvent.IDAttribute),
|
||||
handler.NewCol(LDAPFirstNameAttributeCol, idpEvent.FirstNameAttribute),
|
||||
handler.NewCol(LDAPLastNameAttributeCol, idpEvent.LastNameAttribute),
|
||||
handler.NewCol(LDAPDisplayNameAttributeCol, idpEvent.DisplayNameAttribute),
|
||||
handler.NewCol(LDAPNickNameAttributeCol, idpEvent.NickNameAttribute),
|
||||
handler.NewCol(LDAPPreferredUsernameAttributeCol, idpEvent.PreferredUsernameAttribute),
|
||||
handler.NewCol(LDAPEmailAttributeCol, idpEvent.EmailAttribute),
|
||||
handler.NewCol(LDAPEmailVerifiedAttributeCol, idpEvent.EmailVerifiedAttribute),
|
||||
handler.NewCol(LDAPPhoneAttributeCol, idpEvent.PhoneAttribute),
|
||||
handler.NewCol(LDAPPhoneVerifiedAttributeCol, idpEvent.PhoneVerifiedAttribute),
|
||||
handler.NewCol(LDAPPreferredLanguageAttributeCol, idpEvent.PreferredLanguageAttribute),
|
||||
handler.NewCol(LDAPAvatarURLAttributeCol, idpEvent.AvatarURLAttribute),
|
||||
handler.NewCol(LDAPProfileAttributeCol, idpEvent.ProfileAttribute),
|
||||
},
|
||||
crdb.WithTableSuffix(IDPTemplateLDAPSuffix),
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceLDAPIDPChanged(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.LDAPIDPChangedEvent
|
||||
switch e := event.(type) {
|
||||
case *org.LDAPIDPChangedEvent:
|
||||
idpEvent = e.LDAPIDPChangedEvent
|
||||
case *instance.LDAPIDPChangedEvent:
|
||||
idpEvent = e.LDAPIDPChangedEvent
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-p1582ks", "reduce.wrong.event.type %v", []eventstore.EventType{org.LDAPIDPChangedEventType, instance.LDAPIDPChangedEventType})
|
||||
}
|
||||
|
||||
cols := reduceLDAPIDPChangedTemplateColumns(idpEvent)
|
||||
ldapCols := reduceLDAPIDPChangedLDAPColumns(idpEvent)
|
||||
|
||||
ops := make([]func(eventstore.Event) crdb.Exec, 0, 2)
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
cols,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
if len(ldapCols) > 0 {
|
||||
ops = append(ops,
|
||||
crdb.AddUpdateStatement(
|
||||
ldapCols,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(LDAPIDCol, idpEvent.ID),
|
||||
handler.NewCond(LDAPInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
},
|
||||
crdb.WithTableSuffix(IDPTemplateLDAPSuffix),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return crdb.NewMultiStatement(
|
||||
&idpEvent,
|
||||
ops...,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceIDPRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||
var idpEvent idp.RemovedEvent
|
||||
switch e := event.(type) {
|
||||
case *org.IDPRemovedEvent:
|
||||
idpEvent = e.RemovedEvent
|
||||
case *instance.IDPRemovedEvent:
|
||||
idpEvent = e.RemovedEvent
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-xbcvwin2", "reduce.wrong.event.type %v", []eventstore.EventType{org.IDPRemovedEventType, instance.IDPRemovedEventType})
|
||||
}
|
||||
|
||||
return crdb.NewDeleteStatement(
|
||||
&idpEvent,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPTemplateIDCol, idpEvent.ID),
|
||||
handler.NewCond(IDPTemplateInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *idpTemplateProjection) reduceOwnerRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, ok := event.(*org.OrgRemovedEvent)
|
||||
if !ok {
|
||||
return nil, errors.ThrowInvalidArgumentf(nil, "PROJE-Jp0D2K", "reduce.wrong.event.type %s", org.OrgRemovedEventType)
|
||||
}
|
||||
|
||||
return crdb.NewUpdateStatement(
|
||||
e,
|
||||
[]handler.Column{
|
||||
handler.NewCol(IDPTemplateChangeDateCol, e.CreationDate()),
|
||||
handler.NewCol(IDPTemplateSequenceCol, e.Sequence()),
|
||||
handler.NewCol(IDPTemplateOwnerRemovedCol, true),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(IDPTemplateInstanceIDCol, e.Aggregate().InstanceID),
|
||||
handler.NewCond(IDPTemplateResourceOwnerCol, e.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func reduceLDAPIDPChangedTemplateColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
cols := make([]handler.Column, 0, 7)
|
||||
if idpEvent.Name != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateNameCol, *idpEvent.Name))
|
||||
}
|
||||
if idpEvent.IsCreationAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsCreationAllowedCol, *idpEvent.IsCreationAllowed))
|
||||
}
|
||||
if idpEvent.IsLinkingAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsLinkingAllowedCol, *idpEvent.IsLinkingAllowed))
|
||||
}
|
||||
if idpEvent.IsAutoCreation != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoCreationCol, *idpEvent.IsAutoCreation))
|
||||
}
|
||||
if idpEvent.IsAutoUpdate != nil {
|
||||
cols = append(cols, handler.NewCol(IDPTemplateIsAutoUpdateCol, *idpEvent.IsAutoUpdate))
|
||||
}
|
||||
return append(cols,
|
||||
handler.NewCol(IDPTemplateChangeDateCol, idpEvent.CreationDate()),
|
||||
handler.NewCol(IDPTemplateSequenceCol, idpEvent.Sequence()),
|
||||
)
|
||||
}
|
||||
|
||||
func reduceLDAPIDPChangedLDAPColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
ldapCols := make([]handler.Column, 0, 4)
|
||||
if idpEvent.Host != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPHostCol, *idpEvent.Host))
|
||||
}
|
||||
if idpEvent.Port != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPortCol, *idpEvent.Port))
|
||||
}
|
||||
if idpEvent.TLS != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPTlsCol, *idpEvent.TLS))
|
||||
}
|
||||
if idpEvent.BaseDN != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPBaseDNCol, *idpEvent.BaseDN))
|
||||
}
|
||||
if idpEvent.UserObjectClass != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserObjectClassCol, *idpEvent.UserObjectClass))
|
||||
}
|
||||
if idpEvent.UserUniqueAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserUniqueAttributeCol, *idpEvent.UserUniqueAttribute))
|
||||
}
|
||||
if idpEvent.Admin != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPAdminCol, *idpEvent.Admin))
|
||||
}
|
||||
if idpEvent.Password != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPasswordCol, *idpEvent.Password))
|
||||
}
|
||||
if idpEvent.IDAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPIDAttributeCol, *idpEvent.IDAttribute))
|
||||
}
|
||||
if idpEvent.FirstNameAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPFirstNameAttributeCol, *idpEvent.FirstNameAttribute))
|
||||
}
|
||||
if idpEvent.LastNameAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPLastNameAttributeCol, *idpEvent.LastNameAttribute))
|
||||
}
|
||||
if idpEvent.DisplayNameAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPDisplayNameAttributeCol, *idpEvent.DisplayNameAttribute))
|
||||
}
|
||||
if idpEvent.NickNameAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPNickNameAttributeCol, *idpEvent.NickNameAttribute))
|
||||
}
|
||||
if idpEvent.PreferredUsernameAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPreferredUsernameAttributeCol, *idpEvent.PreferredUsernameAttribute))
|
||||
}
|
||||
if idpEvent.EmailAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPEmailAttributeCol, *idpEvent.EmailAttribute))
|
||||
}
|
||||
if idpEvent.EmailVerifiedAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPEmailVerifiedAttributeCol, *idpEvent.EmailVerifiedAttribute))
|
||||
}
|
||||
if idpEvent.PhoneAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPhoneAttributeCol, *idpEvent.PhoneAttribute))
|
||||
}
|
||||
if idpEvent.PhoneVerifiedAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPhoneVerifiedAttributeCol, *idpEvent.PhoneVerifiedAttribute))
|
||||
}
|
||||
if idpEvent.PreferredLanguageAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPreferredLanguageAttributeCol, *idpEvent.PreferredLanguageAttribute))
|
||||
}
|
||||
if idpEvent.AvatarURLAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPAvatarURLAttributeCol, *idpEvent.AvatarURLAttribute))
|
||||
}
|
||||
if idpEvent.ProfileAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPProfileAttributeCol, *idpEvent.ProfileAttribute))
|
||||
}
|
||||
return ldapCols
|
||||
}
|
515
internal/query/projection/idp_template_test.go
Normal file
515
internal/query/projection/idp_template_test.go
Normal file
@ -0,0 +1,515 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
func TestIDPTemplateProjection_reducesRemove(t *testing.T) {
|
||||
type args struct {
|
||||
event func(t *testing.T) eventstore.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||
want wantReduce
|
||||
}{
|
||||
|
||||
{
|
||||
name: "instance reduceInstanceRemoved",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.InstanceRemovedEventType),
|
||||
instance.AggregateType,
|
||||
nil,
|
||||
), instance.InstanceRemovedEventMapper),
|
||||
},
|
||||
reduce: reduceInstanceRemovedHelper(IDPInstanceIDCol),
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.idp_templates WHERE (instance_id = $1)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org reduceOwnerRemoved",
|
||||
reduce: (&idpTemplateProjection{}).reduceOwnerRemoved,
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(org.OrgRemovedEventType),
|
||||
org.AggregateType,
|
||||
nil,
|
||||
), org.OrgRemovedEventMapper),
|
||||
},
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("org"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
true,
|
||||
"instance-id",
|
||||
"agg-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org reduceIDPRemoved",
|
||||
reduce: (&idpTemplateProjection{}).reduceIDPRemoved,
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(org.IDPRemovedEventType),
|
||||
org.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id"
|
||||
}`),
|
||||
), org.IDPRemovedEventMapper),
|
||||
},
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("org"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.idp_templates WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := baseEvent(t)
|
||||
got, err := tt.reduce(event)
|
||||
if !errors.IsErrorInvalidArgument(err) {
|
||||
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||
}
|
||||
|
||||
event = tt.args.event(t)
|
||||
got, err = tt.reduce(event)
|
||||
assertReduce(t, got, err, IDPTemplateTable, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
type args struct {
|
||||
event func(t *testing.T) eventstore.Event
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||
want wantReduce
|
||||
}{
|
||||
{
|
||||
name: "instance reduceLDAPIDPAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.LDAPIDPAddedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
"displayNameAttribute": "display",
|
||||
"nickNameAttribute": "nickname",
|
||||
"preferredUsernameAttribute": "username",
|
||||
"emailAttribute": "email",
|
||||
"emailVerifiedAttribute": "email_verified",
|
||||
"phoneAttribute": "phone",
|
||||
"phoneVerifiedAttribute": "phone_verified",
|
||||
"preferredLanguageAttribute": "lang",
|
||||
"avatarURLAttribute": "avatar",
|
||||
"profileAttribute": "profile",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), instance.LDAPIDPAddedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceLDAPIDPAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, owner_type, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"ro-id",
|
||||
"instance-id",
|
||||
domain.IDPStateActive,
|
||||
"custom-zitadel-instance",
|
||||
domain.IdentityProviderTypeSystem,
|
||||
domain.IDPTypeLDAP,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
anyArg{},
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"email_verified",
|
||||
"phone",
|
||||
"phone_verified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org reduceLDAPIDPAdded",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(org.LDAPIDPAddedEventType),
|
||||
org.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
"displayNameAttribute": "display",
|
||||
"nickNameAttribute": "nickname",
|
||||
"preferredUsernameAttribute": "username",
|
||||
"emailAttribute": "email",
|
||||
"emailVerifiedAttribute": "email_verified",
|
||||
"phoneAttribute": "phone",
|
||||
"phoneVerifiedAttribute": "phone_verified",
|
||||
"preferredLanguageAttribute": "lang",
|
||||
"avatarURLAttribute": "avatar",
|
||||
"profileAttribute": "profile",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), org.LDAPIDPAddedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceLDAPIDPAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("org"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates (id, creation_date, change_date, sequence, resource_owner, instance_id, state, name, owner_type, type, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"ro-id",
|
||||
"instance-id",
|
||||
domain.IDPStateActive,
|
||||
"custom-zitadel-instance",
|
||||
domain.IdentityProviderTypeOrg,
|
||||
domain.IDPTypeLDAP,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
anyArg{},
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"email_verified",
|
||||
"phone",
|
||||
"phone_verified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceLDAPIDPChanged minimal",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.LDAPIDPChangedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host"
|
||||
}`),
|
||||
), instance.LDAPIDPChangedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceLDAPIDPChanged,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (name, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
"custom-zitadel-instance",
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates_ldap SET host = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"host",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "instance reduceLDAPIDPChanged",
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(instance.LDAPIDPChangedEventType),
|
||||
instance.AggregateType,
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
"displayNameAttribute": "display",
|
||||
"nickNameAttribute": "nickname",
|
||||
"preferredUsernameAttribute": "username",
|
||||
"emailAttribute": "email",
|
||||
"emailVerifiedAttribute": "email_verified",
|
||||
"phoneAttribute": "phone",
|
||||
"phoneVerifiedAttribute": "phone_verified",
|
||||
"preferredLanguageAttribute": "lang",
|
||||
"avatarURLAttribute": "avatar",
|
||||
"profileAttribute": "profile",
|
||||
"isCreationAllowed": true,
|
||||
"isLinkingAllowed": true,
|
||||
"isAutoCreation": true,
|
||||
"isAutoUpdate": true
|
||||
}`),
|
||||
), instance.LDAPIDPChangedEventMapper),
|
||||
},
|
||||
reduce: (&idpTemplateProjection{}).reduceLDAPIDPChanged,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("instance"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (name, is_creation_allowed, is_linking_allowed, is_auto_creation, is_auto_update, change_date, sequence) = ($1, $2, $3, $4, $5, $6, $7) WHERE (id = $8) AND (instance_id = $9)",
|
||||
expectedArgs: []interface{}{
|
||||
"custom-zitadel-instance",
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates_ldap SET (host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) WHERE (idp_id = $22) AND (instance_id = $23)",
|
||||
expectedArgs: []interface{}{
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
anyArg{},
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
"display",
|
||||
"nickname",
|
||||
"username",
|
||||
"email",
|
||||
"email_verified",
|
||||
"phone",
|
||||
"phone_verified",
|
||||
"lang",
|
||||
"avatar",
|
||||
"profile",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org.reduceOwnerRemoved",
|
||||
reduce: (&idpProjection{}).reduceOwnerRemoved,
|
||||
args: args{
|
||||
event: getEvent(testEvent(
|
||||
repository.EventType(org.OrgRemovedEventType),
|
||||
org.AggregateType,
|
||||
nil,
|
||||
), org.OrgRemovedEventMapper),
|
||||
},
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("org"),
|
||||
sequence: 15,
|
||||
previousSequence: 10,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates SET (change_date, sequence, owner_removed) = ($1, $2, $3) WHERE (instance_id = $4) AND (resource_owner = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
true,
|
||||
"instance-id",
|
||||
"agg-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := baseEvent(t)
|
||||
got, err := tt.reduce(event)
|
||||
if !errors.IsErrorInvalidArgument(err) {
|
||||
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||
}
|
||||
|
||||
event = tt.args.event(t)
|
||||
got, err = tt.reduce(event)
|
||||
assertReduce(t, got, err, IDPTemplateTable, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ var (
|
||||
AppProjection *appProjection
|
||||
IDPUserLinkProjection *idpUserLinkProjection
|
||||
IDPLoginPolicyLinkProjection *idpLoginPolicyLinkProjection
|
||||
IDPTemplateProjection *idpTemplateProjection
|
||||
MailTemplateProjection *mailTemplateProjection
|
||||
MessageTextProjection *messageTextProjection
|
||||
CustomTextProjection *customTextProjection
|
||||
@ -111,6 +112,7 @@ func Create(ctx context.Context, sqlClient *sql.DB, es *eventstore.Eventstore, c
|
||||
AppProjection = newAppProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["apps"]))
|
||||
IDPUserLinkProjection = newIDPUserLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_user_links"]))
|
||||
IDPLoginPolicyLinkProjection = newIDPLoginPolicyLinkProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_login_policy_links"]))
|
||||
IDPTemplateProjection = newIDPTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["idp_templates"]))
|
||||
MailTemplateProjection = newMailTemplateProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["mail_templates"]))
|
||||
MessageTextProjection = newMessageTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["message_texts"]))
|
||||
CustomTextProjection = newCustomTextProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["custom_texts"]))
|
||||
@ -199,6 +201,7 @@ func newProjectionsList() {
|
||||
OrgDomainProjection,
|
||||
LoginPolicyProjection,
|
||||
IDPProjection,
|
||||
IDPTemplateProjection,
|
||||
AppProjection,
|
||||
IDPUserLinkProjection,
|
||||
IDPLoginPolicyLinkProjection,
|
||||
|
104
internal/repository/idp/idp.go
Normal file
104
internal/repository/idp/idp.go
Normal file
@ -0,0 +1,104 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
IsCreationAllowed bool `json:"isCreationAllowed,omitempty"`
|
||||
IsLinkingAllowed bool `json:"isLinkingAllowed,omitempty"`
|
||||
IsAutoCreation bool `json:"isAutoCreation,omitempty"`
|
||||
IsAutoUpdate bool `json:"isAutoUpdate,omitempty"`
|
||||
}
|
||||
|
||||
type OptionChanges struct {
|
||||
IsCreationAllowed *bool `json:"isCreationAllowed,omitempty"`
|
||||
IsLinkingAllowed *bool `json:"isLinkingAllowed,omitempty"`
|
||||
IsAutoCreation *bool `json:"isAutoCreation,omitempty"`
|
||||
IsAutoUpdate *bool `json:"isAutoUpdate,omitempty"`
|
||||
}
|
||||
|
||||
func (o *Options) Changes(options Options) OptionChanges {
|
||||
opts := OptionChanges{}
|
||||
if o.IsCreationAllowed != options.IsCreationAllowed {
|
||||
opts.IsCreationAllowed = &options.IsCreationAllowed
|
||||
}
|
||||
if o.IsLinkingAllowed != options.IsLinkingAllowed {
|
||||
opts.IsLinkingAllowed = &options.IsLinkingAllowed
|
||||
}
|
||||
if o.IsAutoCreation != options.IsAutoCreation {
|
||||
opts.IsAutoCreation = &options.IsAutoCreation
|
||||
}
|
||||
if o.IsAutoUpdate != options.IsAutoUpdate {
|
||||
opts.IsAutoUpdate = &options.IsAutoUpdate
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func (o *Options) ReduceChanges(changes OptionChanges) {
|
||||
if changes.IsCreationAllowed != nil {
|
||||
o.IsCreationAllowed = *changes.IsCreationAllowed
|
||||
}
|
||||
if changes.IsLinkingAllowed != nil {
|
||||
o.IsLinkingAllowed = *changes.IsLinkingAllowed
|
||||
}
|
||||
if changes.IsAutoUpdate != nil {
|
||||
o.IsAutoUpdate = *changes.IsAutoUpdate
|
||||
}
|
||||
if changes.IsAutoUpdate != nil {
|
||||
o.IsAutoUpdate = *changes.IsAutoUpdate
|
||||
}
|
||||
}
|
||||
|
||||
func (o *OptionChanges) IsZero() bool {
|
||||
return o.IsCreationAllowed == nil && o.IsLinkingAllowed == nil && o.IsAutoCreation == nil && o.IsAutoUpdate == nil
|
||||
}
|
||||
|
||||
type RemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
func NewRemovedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id string,
|
||||
name string,
|
||||
) *RemovedEvent {
|
||||
return &RemovedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *RemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
if e.name == "" {
|
||||
return nil
|
||||
}
|
||||
return []*eventstore.EventUniqueConstraint{idpconfig.NewRemoveIDPConfigNameUniqueConstraint(e.name, e.Aggregate().ResourceOwner)}
|
||||
}
|
||||
|
||||
func RemovedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &RemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "IDP-plSD2", "unable to unmarshal event")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
351
internal/repository/idp/ldap.go
Normal file
351
internal/repository/idp/ldap.go
Normal file
@ -0,0 +1,351 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port,omitempty"`
|
||||
TLS bool `json:"tls"`
|
||||
BaseDN string `json:"baseDN"`
|
||||
UserObjectClass string `json:"userObjectClass"`
|
||||
UserUniqueAttribute string `json:"userUniqueAttribute"`
|
||||
Admin string `json:"admin"`
|
||||
Password *crypto.CryptoValue `json:"password"`
|
||||
|
||||
LDAPAttributes
|
||||
Options
|
||||
}
|
||||
|
||||
type LDAPAttributes struct {
|
||||
IDAttribute string `json:"idAttribute,omitempty"`
|
||||
FirstNameAttribute string `json:"firstNameAttribute,omitempty"`
|
||||
LastNameAttribute string `json:"lastNameAttribute,omitempty"`
|
||||
DisplayNameAttribute string `json:"displayNameAttribute,omitempty"`
|
||||
NickNameAttribute string `json:"nickNameAttribute,omitempty"`
|
||||
PreferredUsernameAttribute string `json:"preferredUsernameAttribute,omitempty"`
|
||||
EmailAttribute string `json:"emailAttribute,omitempty"`
|
||||
EmailVerifiedAttribute string `json:"emailVerifiedAttribute,omitempty"`
|
||||
PhoneAttribute string `json:"phoneAttribute,omitempty"`
|
||||
PhoneVerifiedAttribute string `json:"phoneVerifiedAttribute,omitempty"`
|
||||
PreferredLanguageAttribute string `json:"preferredLanguageAttribute,omitempty"`
|
||||
AvatarURLAttribute string `json:"avatarURLAttribute,omitempty"`
|
||||
ProfileAttribute string `json:"profileAttribute,omitempty"`
|
||||
}
|
||||
|
||||
func (o *LDAPAttributes) Changes(attributes LDAPAttributes) LDAPAttributeChanges {
|
||||
attrs := LDAPAttributeChanges{}
|
||||
if o.IDAttribute != attributes.IDAttribute {
|
||||
attrs.IDAttribute = &attributes.IDAttribute
|
||||
}
|
||||
if o.FirstNameAttribute != attributes.FirstNameAttribute {
|
||||
attrs.FirstNameAttribute = &attributes.FirstNameAttribute
|
||||
}
|
||||
if o.LastNameAttribute != attributes.LastNameAttribute {
|
||||
attrs.LastNameAttribute = &attributes.LastNameAttribute
|
||||
}
|
||||
if o.DisplayNameAttribute != attributes.DisplayNameAttribute {
|
||||
attrs.DisplayNameAttribute = &attributes.DisplayNameAttribute
|
||||
}
|
||||
if o.NickNameAttribute != attributes.NickNameAttribute {
|
||||
attrs.NickNameAttribute = &attributes.NickNameAttribute
|
||||
}
|
||||
if o.PreferredUsernameAttribute != attributes.PreferredUsernameAttribute {
|
||||
attrs.PreferredUsernameAttribute = &attributes.PreferredUsernameAttribute
|
||||
}
|
||||
if o.EmailAttribute != attributes.EmailAttribute {
|
||||
attrs.EmailAttribute = &attributes.EmailAttribute
|
||||
}
|
||||
if o.EmailVerifiedAttribute != attributes.EmailVerifiedAttribute {
|
||||
attrs.EmailVerifiedAttribute = &attributes.EmailVerifiedAttribute
|
||||
}
|
||||
if o.PhoneAttribute != attributes.PhoneAttribute {
|
||||
attrs.PhoneAttribute = &attributes.PhoneAttribute
|
||||
}
|
||||
if o.PhoneVerifiedAttribute != attributes.PhoneVerifiedAttribute {
|
||||
attrs.PhoneVerifiedAttribute = &attributes.PhoneVerifiedAttribute
|
||||
}
|
||||
if o.PreferredLanguageAttribute != attributes.PreferredLanguageAttribute {
|
||||
attrs.PreferredLanguageAttribute = &attributes.PreferredLanguageAttribute
|
||||
}
|
||||
if o.AvatarURLAttribute != attributes.AvatarURLAttribute {
|
||||
attrs.AvatarURLAttribute = &attributes.AvatarURLAttribute
|
||||
}
|
||||
if o.ProfileAttribute != attributes.ProfileAttribute {
|
||||
attrs.ProfileAttribute = &attributes.ProfileAttribute
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func (o *LDAPAttributes) ReduceChanges(changes LDAPAttributeChanges) {
|
||||
if changes.IDAttribute != nil {
|
||||
o.IDAttribute = *changes.IDAttribute
|
||||
}
|
||||
if changes.FirstNameAttribute != nil {
|
||||
o.FirstNameAttribute = *changes.FirstNameAttribute
|
||||
}
|
||||
if changes.LastNameAttribute != nil {
|
||||
o.LastNameAttribute = *changes.LastNameAttribute
|
||||
}
|
||||
if changes.DisplayNameAttribute != nil {
|
||||
o.DisplayNameAttribute = *changes.DisplayNameAttribute
|
||||
}
|
||||
if changes.NickNameAttribute != nil {
|
||||
o.NickNameAttribute = *changes.NickNameAttribute
|
||||
}
|
||||
if changes.PreferredUsernameAttribute != nil {
|
||||
o.PreferredUsernameAttribute = *changes.PreferredUsernameAttribute
|
||||
}
|
||||
if changes.EmailAttribute != nil {
|
||||
o.EmailAttribute = *changes.EmailAttribute
|
||||
}
|
||||
if changes.EmailVerifiedAttribute != nil {
|
||||
o.EmailVerifiedAttribute = *changes.EmailVerifiedAttribute
|
||||
}
|
||||
if changes.PhoneAttribute != nil {
|
||||
o.PhoneAttribute = *changes.PhoneAttribute
|
||||
}
|
||||
if changes.PhoneVerifiedAttribute != nil {
|
||||
o.PhoneVerifiedAttribute = *changes.PhoneVerifiedAttribute
|
||||
}
|
||||
if changes.PreferredLanguageAttribute != nil {
|
||||
o.PreferredLanguageAttribute = *changes.PreferredLanguageAttribute
|
||||
}
|
||||
if changes.AvatarURLAttribute != nil {
|
||||
o.AvatarURLAttribute = *changes.AvatarURLAttribute
|
||||
}
|
||||
if changes.ProfileAttribute != nil {
|
||||
o.ProfileAttribute = *changes.ProfileAttribute
|
||||
}
|
||||
}
|
||||
|
||||
func NewLDAPIDPAddedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
attributes LDAPAttributes,
|
||||
options Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
return &LDAPIDPAddedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
Name: name,
|
||||
Host: host,
|
||||
Port: port,
|
||||
TLS: tls,
|
||||
BaseDN: baseDN,
|
||||
UserObjectClass: userObjectClass,
|
||||
UserUniqueAttribute: userUniqueAttribute,
|
||||
Admin: admin,
|
||||
Password: password,
|
||||
LDAPAttributes: attributes,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *LDAPIDPAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *LDAPIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)}
|
||||
}
|
||||
|
||||
func LDAPIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &LDAPIDPAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "IDP-Dgh42", "unable to unmarshal event")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type LDAPIDPChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
oldName string
|
||||
|
||||
ID string `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Host *string `json:"host,omitempty"`
|
||||
Port *string `json:"port,omitempty"`
|
||||
TLS *bool `json:"tls,omitempty"`
|
||||
BaseDN *string `json:"baseDN,omitempty"`
|
||||
UserObjectClass *string `json:"userObjectClass,omitempty"`
|
||||
UserUniqueAttribute *string `json:"userUniqueAttribute,omitempty"`
|
||||
Admin *string `json:"admin,omitempty"`
|
||||
Password *crypto.CryptoValue `json:"password,omitempty"`
|
||||
|
||||
LDAPAttributeChanges
|
||||
OptionChanges
|
||||
}
|
||||
|
||||
type LDAPAttributeChanges struct {
|
||||
IDAttribute *string `json:"idAttribute,omitempty"`
|
||||
FirstNameAttribute *string `json:"firstNameAttribute,omitempty"`
|
||||
LastNameAttribute *string `json:"lastNameAttribute,omitempty"`
|
||||
DisplayNameAttribute *string `json:"displayNameAttribute,omitempty"`
|
||||
NickNameAttribute *string `json:"nickNameAttribute,omitempty"`
|
||||
PreferredUsernameAttribute *string `json:"preferredUsernameAttribute,omitempty"`
|
||||
EmailAttribute *string `json:"emailAttribute,omitempty"`
|
||||
EmailVerifiedAttribute *string `json:"emailVerifiedAttribute,omitempty"`
|
||||
PhoneAttribute *string `json:"phoneAttribute,omitempty"`
|
||||
PhoneVerifiedAttribute *string `json:"phoneVerifiedAttribute,omitempty"`
|
||||
PreferredLanguageAttribute *string `json:"preferredLanguageAttribute,omitempty"`
|
||||
AvatarURLAttribute *string `json:"avatarURLAttribute,omitempty"`
|
||||
ProfileAttribute *string `json:"profileAttribute,omitempty"`
|
||||
}
|
||||
|
||||
func (o LDAPAttributeChanges) IsZero() bool {
|
||||
return o.IDAttribute == nil &&
|
||||
o.FirstNameAttribute == nil &&
|
||||
o.LastNameAttribute == nil &&
|
||||
o.DisplayNameAttribute == nil &&
|
||||
o.NickNameAttribute == nil &&
|
||||
o.PreferredUsernameAttribute == nil &&
|
||||
o.EmailAttribute == nil &&
|
||||
o.EmailVerifiedAttribute == nil &&
|
||||
o.PhoneAttribute == nil &&
|
||||
o.PhoneVerifiedAttribute == nil &&
|
||||
o.PreferredLanguageAttribute == nil &&
|
||||
o.AvatarURLAttribute == nil &&
|
||||
o.ProfileAttribute == nil
|
||||
}
|
||||
|
||||
func NewLDAPIDPChangedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id string,
|
||||
oldName string,
|
||||
changes []LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "IDP-SDf3f", "Errors.NoChangesFound")
|
||||
}
|
||||
changedEvent := &LDAPIDPChangedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
oldName: oldName,
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changedEvent)
|
||||
}
|
||||
return changedEvent, nil
|
||||
}
|
||||
|
||||
type LDAPIDPChanges func(*LDAPIDPChangedEvent)
|
||||
|
||||
func ChangeLDAPName(name string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Name = &name
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPHost(host string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Host = &host
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPPort(port string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Port = &port
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPTLS(tls bool) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.TLS = &tls
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPBaseDN(basDN string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.BaseDN = &basDN
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPUserObjectClass(userObjectClass string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.UserObjectClass = &userObjectClass
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPUserUniqueAttribute(userUniqueAttribute string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.UserUniqueAttribute = &userUniqueAttribute
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPAdmin(admin string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Admin = &admin
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPPassword(password *crypto.CryptoValue) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Password = password
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPAttributes(attributes LDAPAttributeChanges) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.LDAPAttributeChanges = attributes
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPOptions(options OptionChanges) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.OptionChanges = options
|
||||
}
|
||||
}
|
||||
|
||||
func (e *LDAPIDPChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *LDAPIDPChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
if e.Name == nil || e.oldName == *e.Name { // TODO: nil check should be enough?
|
||||
return nil
|
||||
}
|
||||
return []*eventstore.EventUniqueConstraint{
|
||||
idpconfig.NewRemoveIDPConfigNameUniqueConstraint(e.oldName, e.Aggregate().ResourceOwner),
|
||||
idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner),
|
||||
}
|
||||
}
|
||||
|
||||
func LDAPIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e := &LDAPIDPChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "IDP-Sfth3", "unable to unmarshal event")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
@ -70,6 +70,9 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(AggregateType, IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigAddedEventType, IDPJWTConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigChangedEventType, IDPJWTConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPAddedEventType, LDAPIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPChangedEventType, LDAPIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPRemovedEventType, IDPRemovedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LoginPolicyIDPProviderAddedEventType, IdentityProviderAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LoginPolicyIDPProviderRemovedEventType, IdentityProviderRemovedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LoginPolicyIDPProviderCascadeRemovedEventType, IdentityProviderCascadeRemovedEventMapper).
|
||||
|
142
internal/repository/instance/idp.go
Normal file
142
internal/repository/instance/idp.go
Normal file
@ -0,0 +1,142 @@
|
||||
package instance
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
)
|
||||
|
||||
const (
|
||||
LDAPIDPAddedEventType eventstore.EventType = "instance.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "instance.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "instance.idp.removed"
|
||||
)
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
idp.LDAPIDPAddedEvent
|
||||
}
|
||||
|
||||
func NewLDAPIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
|
||||
return &LDAPIDPAddedEvent{
|
||||
LDAPIDPAddedEvent: *idp.NewLDAPIDPAddedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
LDAPIDPAddedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
attributes,
|
||||
options,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func LDAPIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.LDAPIDPAddedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LDAPIDPAddedEvent{LDAPIDPAddedEvent: *e.(*idp.LDAPIDPAddedEvent)}, nil
|
||||
}
|
||||
|
||||
type LDAPIDPChangedEvent struct {
|
||||
idp.LDAPIDPChangedEvent
|
||||
}
|
||||
|
||||
func NewLDAPIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName string,
|
||||
changes []idp.LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
|
||||
changedEvent, err := idp.NewLDAPIDPChangedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
LDAPIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
oldName,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LDAPIDPChangedEvent{LDAPIDPChangedEvent: *changedEvent}, nil
|
||||
}
|
||||
|
||||
func LDAPIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.LDAPIDPChangedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LDAPIDPChangedEvent{LDAPIDPChangedEvent: *e.(*idp.LDAPIDPChangedEvent)}, nil
|
||||
}
|
||||
|
||||
type IDPRemovedEvent struct {
|
||||
idp.RemovedEvent
|
||||
}
|
||||
|
||||
func NewIDPRemovedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
name string,
|
||||
) *IDPRemovedEvent {
|
||||
return &IDPRemovedEvent{
|
||||
RemovedEvent: *idp.NewRemovedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
IDPRemovedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *IDPRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func IDPRemovedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.RemovedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &IDPRemovedEvent{RemovedEvent: *e.(*idp.RemovedEvent)}, nil
|
||||
}
|
@ -78,6 +78,9 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(AggregateType, IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigAddedEventType, IDPJWTConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPJWTConfigChangedEventType, IDPJWTConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPAddedEventType, LDAPIDPAddedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, LDAPIDPChangedEventType, LDAPIDPChangedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, IDPRemovedEventType, IDPRemovedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, TriggerActionsSetEventType, TriggerActionsSetEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, TriggerActionsCascadeRemovedEventType, TriggerActionsCascadeRemovedEventMapper).
|
||||
RegisterFilterEventMapper(AggregateType, FlowClearedEventType, FlowClearedEventMapper).
|
||||
|
142
internal/repository/org/idp.go
Normal file
142
internal/repository/org/idp.go
Normal file
@ -0,0 +1,142 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
)
|
||||
|
||||
const (
|
||||
LDAPIDPAddedEventType eventstore.EventType = "org.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "org.idp.ldap.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "org.idp.removed"
|
||||
)
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
idp.LDAPIDPAddedEvent
|
||||
}
|
||||
|
||||
func NewLDAPIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
|
||||
return &LDAPIDPAddedEvent{
|
||||
LDAPIDPAddedEvent: *idp.NewLDAPIDPAddedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
LDAPIDPAddedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
attributes,
|
||||
options,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func LDAPIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.LDAPIDPAddedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LDAPIDPAddedEvent{LDAPIDPAddedEvent: *e.(*idp.LDAPIDPAddedEvent)}, nil
|
||||
}
|
||||
|
||||
type LDAPIDPChangedEvent struct {
|
||||
idp.LDAPIDPChangedEvent
|
||||
}
|
||||
|
||||
func NewLDAPIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName string,
|
||||
changes []idp.LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
|
||||
changedEvent, err := idp.NewLDAPIDPChangedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
LDAPIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
oldName,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LDAPIDPChangedEvent{LDAPIDPChangedEvent: *changedEvent}, nil
|
||||
}
|
||||
|
||||
func LDAPIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.LDAPIDPChangedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LDAPIDPChangedEvent{LDAPIDPChangedEvent: *e.(*idp.LDAPIDPChangedEvent)}, nil
|
||||
}
|
||||
|
||||
type IDPRemovedEvent struct {
|
||||
idp.RemovedEvent
|
||||
}
|
||||
|
||||
func NewIDPRemovedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
name string,
|
||||
) *IDPRemovedEvent {
|
||||
return &IDPRemovedEvent{
|
||||
RemovedEvent: *idp.NewRemovedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
IDPRemovedEventType,
|
||||
),
|
||||
id,
|
||||
name,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *IDPRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func IDPRemovedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
e, err := idp.RemovedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &IDPRemovedEvent{RemovedEvent: *e.(*idp.RemovedEvent)}, nil
|
||||
}
|
@ -1009,6 +1009,67 @@ service AdminService {
|
||||
};
|
||||
}
|
||||
|
||||
// Returns all identity providers, which match the query
|
||||
// Limit should always be set, there is a default limit set by the service
|
||||
rpc ListProviders(ListProvidersRequest) returns (ListProvidersResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/templates/_search"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.read"
|
||||
};
|
||||
}
|
||||
|
||||
// Returns an identity provider of the instance
|
||||
rpc GetProviderByID(GetProviderByIDRequest) returns (GetProviderByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/idps/templates/{id}"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.read"
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new ldap identity provider on the instance
|
||||
rpc AddLDAPProvider(AddLDAPProviderRequest) returns (AddLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing ldap identity provider on the instance
|
||||
rpc UpdateLDAPProvider(UpdateLDAPProviderRequest) returns (UpdateLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Remove an identity provider
|
||||
// Will remove all linked providers of this configuration on the users
|
||||
rpc DeleteProvider(DeleteProviderRequest) returns (DeleteProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/templates/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
//deprecated: please use DomainPolicy instead
|
||||
//Returns the Org IAM policy defined by the administrators of ZITADEL
|
||||
rpc GetOrgIAMPolicy(GetOrgIAMPolicyRequest) returns (GetOrgIAMPolicyResponse) {
|
||||
@ -3623,6 +3684,79 @@ message UpdateIDPJWTConfigResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message ListProvidersRequest {
|
||||
//list limitations and ordering
|
||||
zitadel.v1.ListQuery query = 1;
|
||||
//criteria the client is looking for
|
||||
repeated ProviderQuery queries = 2;
|
||||
}
|
||||
|
||||
message ProviderQuery {
|
||||
oneof query {
|
||||
zitadel.idp.v1.IDPIDQuery idp_id_query = 1;
|
||||
zitadel.idp.v1.IDPNameQuery idp_name_query = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ListProvidersResponse {
|
||||
zitadel.v1.ListDetails details = 1;
|
||||
repeated zitadel.idp.v1.Provider result = 2;
|
||||
}
|
||||
|
||||
message GetProviderByIDRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
}
|
||||
|
||||
message GetProviderByIDResponse {
|
||||
zitadel.idp.v1.Provider idp = 1;
|
||||
}
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 3 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 10;
|
||||
zitadel.idp.v1.Options provider_options = 11;
|
||||
}
|
||||
|
||||
message AddLDAPProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 4 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 5;
|
||||
string base_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 10 [(validate.rules).string = {max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message DeleteProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
}
|
||||
|
||||
message DeleteProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message GetOrgIAMPolicyRequest {}
|
||||
|
||||
message GetOrgIAMPolicyResponse {
|
||||
|
@ -233,3 +233,70 @@ enum IDPFieldName {
|
||||
IDP_FIELD_NAME_UNSPECIFIED = 0;
|
||||
IDP_FIELD_NAME_NAME = 1;
|
||||
}
|
||||
|
||||
message Provider {
|
||||
string id = 1;
|
||||
zitadel.v1.ObjectDetails details = 2;
|
||||
IDPState state = 3;
|
||||
string name = 4;
|
||||
IDPOwnerType owner = 5;
|
||||
ProviderType type = 6;
|
||||
ProviderConfig config = 7;
|
||||
}
|
||||
|
||||
enum ProviderType {
|
||||
PROVIDER_TYPE_UNSPECIFIED = 0;
|
||||
PROVIDER_TYPE_OIDC = 1;
|
||||
PROVIDER_TYPE_JWT = 2;
|
||||
PROVIDER_TYPE_LDAP = 3;
|
||||
PROVIDER_TYPE_OAUTH = 4;
|
||||
PROVIDER_TYPE_AZURE_AD = 5;
|
||||
PROVIDER_TYPE_GITHUB = 6;
|
||||
PROVIDER_TYPE_GITHUB_EE = 7;
|
||||
PROVIDER_TYPE_GITLAB = 8;
|
||||
PROVIDER_TYPE_GITLAB_SELF_HOSTED = 9;
|
||||
PROVIDER_TYPE_GOOGLE = 10;
|
||||
}
|
||||
|
||||
message ProviderConfig {
|
||||
Options options = 1;
|
||||
oneof config {
|
||||
LDAPConfig ldap = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message LDAPConfig {
|
||||
string host = 1;
|
||||
string port = 2;
|
||||
bool tls = 3;
|
||||
string base_dn = 4;
|
||||
string user_object_class = 5;
|
||||
string user_unique_attribute = 6;
|
||||
string admin = 7;
|
||||
LDAPAttributes attributes = 8;
|
||||
Options provider_options = 9;
|
||||
}
|
||||
|
||||
message Options {
|
||||
bool is_linking_allowed = 1;
|
||||
bool is_creation_allowed = 2;
|
||||
bool is_auto_creation = 3;
|
||||
bool is_auto_update = 4;
|
||||
}
|
||||
|
||||
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}];
|
||||
}
|
||||
|
||||
|
@ -3007,6 +3007,67 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
// Returns all identity providers, which match the query
|
||||
// Limit should always be set, there is a default limit set by the service
|
||||
rpc ListProviders(ListProvidersRequest) returns (ListProvidersResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/templates/_search"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.read"
|
||||
};
|
||||
}
|
||||
|
||||
// Returns an identity provider of the organisation
|
||||
rpc GetProviderByID(GetProviderByIDRequest) returns (GetProviderByIDResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/idps/templates/{id}"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.read"
|
||||
};
|
||||
}
|
||||
|
||||
// Add a new ldap identity provider in the organisation
|
||||
rpc AddLDAPProvider(AddLDAPProviderRequest) returns (AddLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Change an existing ldap identity provider in the organisation
|
||||
rpc UpdateLDAPProvider(UpdateLDAPProviderRequest) returns (UpdateLDAPProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/ldap/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
// Remove an identity provider
|
||||
// Will remove all linked providers of this configuration on the users
|
||||
rpc DeleteProvider(DeleteProviderRequest) returns (DeleteProviderResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/idps/templates/{id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.idp.write"
|
||||
};
|
||||
}
|
||||
|
||||
rpc ListActions(ListActionsRequest) returns (ListActionsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/actions/_search"
|
||||
@ -5920,6 +5981,80 @@ message UpdateOrgIDPJWTConfigResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message ListProvidersRequest {
|
||||
//list limitations and ordering
|
||||
zitadel.v1.ListQuery query = 1;
|
||||
//criteria the client is looking for
|
||||
repeated ProviderQuery queries = 2;
|
||||
}
|
||||
|
||||
message ProviderQuery {
|
||||
oneof query {
|
||||
zitadel.idp.v1.IDPIDQuery idp_id_query = 1;
|
||||
zitadel.idp.v1.IDPNameQuery idp_name_query = 2;
|
||||
zitadel.idp.v1.IDPOwnerTypeQuery owner_type_query = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ListProvidersResponse {
|
||||
zitadel.v1.ListDetails details = 1;
|
||||
repeated zitadel.idp.v1.Provider result = 2;
|
||||
}
|
||||
|
||||
message GetProviderByIDRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
}
|
||||
|
||||
message GetProviderByIDResponse {
|
||||
zitadel.idp.v1.Provider idp = 1;
|
||||
}
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 3 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 10;
|
||||
zitadel.idp.v1.Options provider_options = 11;
|
||||
}
|
||||
|
||||
message AddLDAPProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
string id = 2;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 4 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 5;
|
||||
string base_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 10 [(validate.rules).string = {max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message DeleteProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
}
|
||||
|
||||
message DeleteProviderResponse {
|
||||
zitadel.v1.ObjectDetails details = 1;
|
||||
}
|
||||
|
||||
message ListActionsRequest {
|
||||
//list limitations and ordering
|
||||
zitadel.v1.ListQuery query = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user