mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-14 03:54:21 +00:00
Merge branch 'main' into next-rc
This commit is contained in:
commit
76c84d385c
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -91,7 +91,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
needs:
|
needs:
|
||||||
[version, core-unit-test, core-integration-test, lint, container, e2e]
|
[version, core-unit-test, core-integration-test, lint, container, e2e]
|
||||||
if: ${{ needs.version.outputs.published == 'true' && github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
secrets:
|
secrets:
|
||||||
GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }}
|
GCR_JSON_KEY_BASE64: ${{ secrets.GCR_JSON_KEY_BASE64 }}
|
||||||
with:
|
with:
|
||||||
|
2
.github/workflows/version.yml
vendored
2
.github/workflows/version.yml
vendored
@ -47,4 +47,4 @@ jobs:
|
|||||||
name: output
|
name: output
|
||||||
id: output
|
id: output
|
||||||
run:
|
run:
|
||||||
if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=" >> "$GITHUB_OUTPUT";fi
|
if [[ ! -z "${{ steps.semantic.outputs.new_release_version }}" ]]; then echo "VERSION=v${{ steps.semantic.outputs.new_release_version }}" >> "$GITHUB_OUTPUT"; else echo "VERSION=${{ github.sha }}" >> "$GITHUB_OUTPUT";fi
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -76,6 +76,7 @@ migrations/cockroach/migrate_cloud.go
|
|||||||
!/.artifacts/zitadel
|
!/.artifacts/zitadel
|
||||||
/zitadel
|
/zitadel
|
||||||
node_modules/
|
node_modules/
|
||||||
|
.kreya
|
||||||
|
|
||||||
go.work
|
go.work
|
||||||
go.work.sum
|
go.work.sum
|
||||||
|
26
cmd/setup/19.go
Normal file
26
cmd/setup/19.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed 19.sql
|
||||||
|
addCurrentSequencesIndex string
|
||||||
|
)
|
||||||
|
|
||||||
|
type AddCurrentSequencesIndex struct {
|
||||||
|
dbClient *database.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *AddCurrentSequencesIndex) Execute(ctx context.Context) error {
|
||||||
|
_, err := mig.dbClient.ExecContext(ctx, addCurrentSequencesIndex)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mig *AddCurrentSequencesIndex) String() string {
|
||||||
|
return "19_add_current_sequences_index"
|
||||||
|
}
|
1
cmd/setup/19.sql
Normal file
1
cmd/setup/19.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX CONCURRENTLY IF NOT EXISTS events2_current_sequence ON eventstore.events2 ("sequence" DESC, aggregate_id, aggregate_type, instance_id);
|
@ -76,6 +76,7 @@ type Steps struct {
|
|||||||
s16UniqueConstraintsLower *UniqueConstraintToLower
|
s16UniqueConstraintsLower *UniqueConstraintToLower
|
||||||
s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates
|
s17AddOffsetToUniqueConstraints *AddOffsetToCurrentStates
|
||||||
s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames
|
s18AddLowerFieldsToLoginNames *AddLowerFieldsToLoginNames
|
||||||
|
s19AddCurrentStatesIndex *AddCurrentSequencesIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
type encryptionKeyConfig struct {
|
type encryptionKeyConfig struct {
|
||||||
|
@ -109,6 +109,7 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
|||||||
steps.s16UniqueConstraintsLower = &UniqueConstraintToLower{dbClient: queryDBClient}
|
steps.s16UniqueConstraintsLower = &UniqueConstraintToLower{dbClient: queryDBClient}
|
||||||
steps.s17AddOffsetToUniqueConstraints = &AddOffsetToCurrentStates{dbClient: queryDBClient}
|
steps.s17AddOffsetToUniqueConstraints = &AddOffsetToCurrentStates{dbClient: queryDBClient}
|
||||||
steps.s18AddLowerFieldsToLoginNames = &AddLowerFieldsToLoginNames{dbClient: queryDBClient}
|
steps.s18AddLowerFieldsToLoginNames = &AddLowerFieldsToLoginNames{dbClient: queryDBClient}
|
||||||
|
steps.s19AddCurrentStatesIndex = &AddCurrentSequencesIndex{dbClient: queryDBClient}
|
||||||
|
|
||||||
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
|
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
|
||||||
logging.OnError(err).Fatal("unable to start projections")
|
logging.OnError(err).Fatal("unable to start projections")
|
||||||
@ -153,6 +154,8 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
|||||||
logging.WithFields("name", steps.s16UniqueConstraintsLower.String()).OnError(err).Fatal("migration failed")
|
logging.WithFields("name", steps.s16UniqueConstraintsLower.String()).OnError(err).Fatal("migration failed")
|
||||||
err = migration.Migrate(ctx, eventstoreClient, steps.s17AddOffsetToUniqueConstraints)
|
err = migration.Migrate(ctx, eventstoreClient, steps.s17AddOffsetToUniqueConstraints)
|
||||||
logging.WithFields("name", steps.s17AddOffsetToUniqueConstraints.String()).OnError(err).Fatal("migration failed")
|
logging.WithFields("name", steps.s17AddOffsetToUniqueConstraints.String()).OnError(err).Fatal("migration failed")
|
||||||
|
err = migration.Migrate(ctx, eventstoreClient, steps.s19AddCurrentStatesIndex)
|
||||||
|
logging.WithFields("name", steps.s19AddCurrentStatesIndex.String()).OnError(err).Fatal("migration failed")
|
||||||
|
|
||||||
for _, repeatableStep := range repeatableSteps {
|
for _, repeatableStep := range repeatableSteps {
|
||||||
err = migration.Migrate(ctx, eventstoreClient, repeatableStep)
|
err = migration.Migrate(ctx, eventstoreClient, repeatableStep)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: Overview of ZITADEL Examples, Quickstarts, and SDKs
|
title: Overview of ZITADEL example applications and quickstarts
|
||||||
sidebar_label: Overview
|
sidebar_label: Overview
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -198,3 +198,12 @@ Our examples cover a range of programming languages and frameworks, so no matter
|
|||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
## Other example applications
|
||||||
|
|
||||||
|
- [B2B customer portal](https://github.com/zitadel/zitadel-nextjs-b2b): Showcase the use of personal access tokens in a B2B environment. Uses NextJS Framework.
|
||||||
|
- [Frontend with backend API](https://github.com/zitadel/example-quote-generator-app): A simple web application using a React front-end and a Python back-end API, both secured using ZITADEL
|
||||||
|
- [Introspection](https://github.com/zitadel/examples-api-access-and-token-introspection): Python examples for securing an API and invoking it as a service user
|
||||||
|
- [Fine-grained authorization](https://github.com/zitadel/example-fine-grained-authorization): Leverage actions, custom metadata, and claims for attribute-based access control
|
||||||
|
|
||||||
|
Search for the "example" tag in our repository to [explore all examples](https://github.com/search?q=topic%3Aexamples+org%3Azitadel&type=repositories).
|
||||||
|
6
go.mod
6
go.mod
@ -60,7 +60,7 @@ require (
|
|||||||
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
|
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
|
||||||
github.com/ttacon/libphonenumber v1.2.1
|
github.com/ttacon/libphonenumber v1.2.1
|
||||||
github.com/zitadel/logging v0.5.0
|
github.com/zitadel/logging v0.5.0
|
||||||
github.com/zitadel/oidc/v3 v3.8.0
|
github.com/zitadel/oidc/v3 v3.8.1
|
||||||
github.com/zitadel/passwap v0.4.0
|
github.com/zitadel/passwap v0.4.0
|
||||||
github.com/zitadel/saml v0.1.3
|
github.com/zitadel/saml v0.1.3
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0
|
||||||
@ -74,7 +74,7 @@ require (
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.20.0
|
go.opentelemetry.io/otel/sdk/metric v1.20.0
|
||||||
go.opentelemetry.io/otel/trace v1.21.0
|
go.opentelemetry.io/otel/trace v1.21.0
|
||||||
go.uber.org/mock v0.3.0
|
go.uber.org/mock v0.3.0
|
||||||
golang.org/x/crypto v0.16.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
|
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
|
||||||
golang.org/x/net v0.19.0
|
golang.org/x/net v0.19.0
|
||||||
golang.org/x/oauth2 v0.15.0
|
golang.org/x/oauth2 v0.15.0
|
||||||
@ -90,7 +90,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.44.0 // indirect
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.44.0 // indirect
|
||||||
github.com/crewjam/httperr v0.2.0 // indirect
|
github.com/crewjam/httperr v0.2.0 // indirect
|
||||||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
github.com/go-chi/chi/v5 v5.0.11 // indirect
|
||||||
github.com/go-logr/logr v1.3.0 // indirect
|
github.com/go-logr/logr v1.3.0 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||||
|
12
go.sum
12
go.sum
@ -258,8 +258,8 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
|
|||||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
|
||||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||||
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||||
@ -867,8 +867,8 @@ github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8=
|
|||||||
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
github.com/zitadel/logging v0.5.0 h1:Kunouvqse/efXy4UDvFw5s3vP+Z4AlHo3y8wF7stXHA=
|
github.com/zitadel/logging v0.5.0 h1:Kunouvqse/efXy4UDvFw5s3vP+Z4AlHo3y8wF7stXHA=
|
||||||
github.com/zitadel/logging v0.5.0/go.mod h1:IzP5fzwFhzzyxHkSmfF8dsyqFsQRJLLcQmwhIBzlGsE=
|
github.com/zitadel/logging v0.5.0/go.mod h1:IzP5fzwFhzzyxHkSmfF8dsyqFsQRJLLcQmwhIBzlGsE=
|
||||||
github.com/zitadel/oidc/v3 v3.8.0 h1:4Nvok+e6o3FDpqrf14JOg4EVBvwXNFOI1lFHPZU75iA=
|
github.com/zitadel/oidc/v3 v3.8.1 h1:YsFWUpT3JFsDlF9ePwM851CymDwqfQ3UU1CoOEOMEdU=
|
||||||
github.com/zitadel/oidc/v3 v3.8.0/go.mod h1:v+aHyg4lBAUuuUHINwXqHtKunPJZo8kPvMpRRBYEKHY=
|
github.com/zitadel/oidc/v3 v3.8.1/go.mod h1:rUKTJBsamKtqurN1MpuRYxF5FgW/9RJ/1/AF3g7/2k0=
|
||||||
github.com/zitadel/passwap v0.4.0 h1:cMaISx+Ve7ilgG7Q8xOli4Z6IWr8Gndss+jeBk5A3O0=
|
github.com/zitadel/passwap v0.4.0 h1:cMaISx+Ve7ilgG7Q8xOli4Z6IWr8Gndss+jeBk5A3O0=
|
||||||
github.com/zitadel/passwap v0.4.0/go.mod h1:yHaDM4A68yRkdic5BZ4iUNoc19hT+kYt8n1/Nz+I87g=
|
github.com/zitadel/passwap v0.4.0/go.mod h1:yHaDM4A68yRkdic5BZ4iUNoc19hT+kYt8n1/Nz+I87g=
|
||||||
github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM=
|
github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM=
|
||||||
@ -953,8 +953,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
|||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/grpc/org"
|
"github.com/zitadel/zitadel/internal/api/grpc/org"
|
||||||
user_grpc "github.com/zitadel/zitadel/internal/api/grpc/user"
|
user_grpc "github.com/zitadel/zitadel/internal/api/grpc/user"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
@ -275,41 +274,6 @@ func ListMyProjectOrgsRequestToQuery(req *auth_pb.ListMyProjectOrgsRequest) (*qu
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func membershipToDomain(memberships []*query.Membership) []*domain.UserMembership {
|
|
||||||
result := make([]*domain.UserMembership, len(memberships))
|
|
||||||
for i, membership := range memberships {
|
|
||||||
typ, displayName, aggID, objID := MemberTypeToDomain(membership)
|
|
||||||
result[i] = &domain.UserMembership{
|
|
||||||
UserID: membership.UserID,
|
|
||||||
MemberType: typ,
|
|
||||||
AggregateID: aggID,
|
|
||||||
ObjectID: objID,
|
|
||||||
Roles: membership.Roles,
|
|
||||||
DisplayName: displayName,
|
|
||||||
CreationDate: membership.CreationDate,
|
|
||||||
ChangeDate: membership.ChangeDate,
|
|
||||||
ResourceOwner: membership.ResourceOwner,
|
|
||||||
//TODO: implement
|
|
||||||
// ResourceOwnerName: membership.ResourceOwnerName,
|
|
||||||
Sequence: membership.Sequence,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func MemberTypeToDomain(m *query.Membership) (_ domain.MemberType, displayName, aggID, objID string) {
|
|
||||||
if m.Org != nil {
|
|
||||||
return domain.MemberTypeOrganisation, m.Org.Name, m.Org.OrgID, ""
|
|
||||||
} else if m.IAM != nil {
|
|
||||||
return domain.MemberTypeIam, m.IAM.Name, m.IAM.IAMID, ""
|
|
||||||
} else if m.Project != nil {
|
|
||||||
return domain.MemberTypeProject, m.Project.Name, m.Project.ProjectID, ""
|
|
||||||
} else if m.ProjectGrant != nil {
|
|
||||||
return domain.MemberTypeProjectGrant, m.ProjectGrant.ProjectName, m.ProjectGrant.ProjectID, m.ProjectGrant.GrantID
|
|
||||||
}
|
|
||||||
return domain.MemberTypeUnspecified, "", "", ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func cascadingMemberships(memberships []*query.Membership) []*command.CascadingMembership {
|
func cascadingMemberships(memberships []*query.Membership) []*command.CascadingMembership {
|
||||||
cascades := make([]*command.CascadingMembership, len(memberships))
|
cascades := make([]*command.CascadingMembership, len(memberships))
|
||||||
for i, membership := range memberships {
|
for i, membership := range memberships {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/idp/providers/azuread"
|
"github.com/zitadel/zitadel/internal/idp/providers/azuread"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||||
@ -255,40 +254,6 @@ func IDPProviderTypeFromPb(typ idp_pb.IDPOwnerType) domain.IdentityProviderType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func IDPProviderTypeModelFromPb(typ idp_pb.IDPOwnerType) iam_model.IDPProviderType {
|
|
||||||
switch typ {
|
|
||||||
case idp_pb.IDPOwnerType_IDP_OWNER_TYPE_ORG:
|
|
||||||
return iam_model.IDPProviderTypeOrg
|
|
||||||
case idp_pb.IDPOwnerType_IDP_OWNER_TYPE_SYSTEM:
|
|
||||||
return iam_model.IDPProviderTypeSystem
|
|
||||||
default:
|
|
||||||
return iam_model.IDPProviderTypeOrg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPIDQueryToModel(query *idp_pb.IDPIDQuery) *iam_model.IDPConfigSearchQuery {
|
|
||||||
return &iam_model.IDPConfigSearchQuery{
|
|
||||||
Key: iam_model.IDPConfigSearchKeyIdpConfigID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: query.Id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPNameQueryToModel(query *idp_pb.IDPNameQuery) *iam_model.IDPConfigSearchQuery {
|
|
||||||
return &iam_model.IDPConfigSearchQuery{
|
|
||||||
Key: iam_model.IDPConfigSearchKeyName,
|
|
||||||
Method: obj_grpc.TextMethodToModel(query.Method),
|
|
||||||
Value: query.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPOwnerTypeQueryToModel(query *idp_pb.IDPOwnerTypeQuery) *iam_model.IDPConfigSearchQuery {
|
|
||||||
return &iam_model.IDPConfigSearchQuery{
|
|
||||||
Key: iam_model.IDPConfigSearchKeyIdpProviderType,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: IDPProviderTypeModelFromPb(query.OwnerType),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func ownerTypeToPB(typ domain.IdentityProviderType) idp_pb.IDPOwnerType {
|
func ownerTypeToPB(typ domain.IdentityProviderType) idp_pb.IDPOwnerType {
|
||||||
switch typ {
|
switch typ {
|
||||||
case domain.IdentityProviderTypeOrg:
|
case domain.IdentityProviderTypeOrg:
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp"
|
idp_pb "github.com/zitadel/zitadel/pkg/grpc/idp"
|
||||||
@ -136,29 +135,6 @@ func idpQueryToModel(idpQuery *mgmt_pb.IDPQuery) (query.SearchQuery, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func idpProviderViewsToDomain(idps []*iam_model.IDPProviderView) []*domain.IDPProvider {
|
|
||||||
idpProvider := make([]*domain.IDPProvider, len(idps))
|
|
||||||
for i, idp := range idps {
|
|
||||||
idpProvider[i] = &domain.IDPProvider{
|
|
||||||
ObjectRoot: models.ObjectRoot{
|
|
||||||
AggregateID: idp.AggregateID,
|
|
||||||
},
|
|
||||||
IDPConfigID: idp.IDPConfigID,
|
|
||||||
Type: idpConfigTypeToDomain(idp.IDPProviderType),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idpProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
func idpConfigTypeToDomain(idpType iam_model.IDPProviderType) domain.IdentityProviderType {
|
|
||||||
switch idpType {
|
|
||||||
case iam_model.IDPProviderTypeOrg:
|
|
||||||
return domain.IdentityProviderTypeOrg
|
|
||||||
default:
|
|
||||||
return domain.IdentityProviderTypeSystem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func userLinksToDomain(idps []*query.IDPUserLink) []*domain.UserIDPLink {
|
func userLinksToDomain(idps []*query.IDPUserLink) []*domain.UserIDPLink {
|
||||||
links := make([]*domain.UserIDPLink, len(idps))
|
links := make([]*domain.UserIDPLink, len(idps))
|
||||||
for i, idp := range idps {
|
for i, idp := range idps {
|
||||||
|
@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
user_model "github.com/zitadel/zitadel/internal/user/model"
|
|
||||||
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
|
mgmt_pb "github.com/zitadel/zitadel/pkg/grpc/management"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -359,38 +358,3 @@ func ListUserMembershipsRequestToModel(ctx context.Context, req *mgmt_pb.ListUse
|
|||||||
Queries: queries,
|
Queries: queries,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UserMembershipViewsToDomain(memberships []*user_model.UserMembershipView) []*domain.UserMembership {
|
|
||||||
result := make([]*domain.UserMembership, len(memberships))
|
|
||||||
for i, membership := range memberships {
|
|
||||||
result[i] = &domain.UserMembership{
|
|
||||||
UserID: membership.UserID,
|
|
||||||
MemberType: MemberTypeToDomain(membership.MemberType),
|
|
||||||
AggregateID: membership.AggregateID,
|
|
||||||
ObjectID: membership.ObjectID,
|
|
||||||
Roles: membership.Roles,
|
|
||||||
DisplayName: membership.DisplayName,
|
|
||||||
CreationDate: membership.CreationDate,
|
|
||||||
ChangeDate: membership.ChangeDate,
|
|
||||||
ResourceOwner: membership.ResourceOwner,
|
|
||||||
ResourceOwnerName: membership.ResourceOwnerName,
|
|
||||||
Sequence: membership.Sequence,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func MemberTypeToDomain(mType user_model.MemberType) domain.MemberType {
|
|
||||||
switch mType {
|
|
||||||
case user_model.MemberTypeIam:
|
|
||||||
return domain.MemberTypeIam
|
|
||||||
case user_model.MemberTypeOrganisation:
|
|
||||||
return domain.MemberTypeOrganisation
|
|
||||||
case user_model.MemberTypeProject:
|
|
||||||
return domain.MemberTypeProject
|
|
||||||
case user_model.MemberTypeProjectGrant:
|
|
||||||
return domain.MemberTypeProjectGrant
|
|
||||||
default:
|
|
||||||
return domain.MemberTypeUnspecified
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,13 +9,6 @@ import (
|
|||||||
member_pb "github.com/zitadel/zitadel/pkg/grpc/member"
|
member_pb "github.com/zitadel/zitadel/pkg/grpc/member"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MemberToDomain(member *member_pb.Member) *domain.Member {
|
|
||||||
return &domain.Member{
|
|
||||||
UserID: member.UserId,
|
|
||||||
Roles: member.Roles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembersToPb(assetAPIPrefix string, members []*query.Member) []*member_pb.Member {
|
func MembersToPb(assetAPIPrefix string, members []*query.Member) []*member_pb.Member {
|
||||||
m := make([]*member_pb.Member, len(members))
|
m := make([]*member_pb.Member, len(members))
|
||||||
for i, member := range members {
|
for i, member := range members {
|
||||||
|
@ -97,29 +97,6 @@ func ToListDetails(
|
|||||||
return details
|
return details
|
||||||
}
|
}
|
||||||
|
|
||||||
func TextMethodToModel(method object_pb.TextQueryMethod) domain.SearchMethod {
|
|
||||||
switch method {
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS:
|
|
||||||
return domain.SearchMethodEquals
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE:
|
|
||||||
return domain.SearchMethodEqualsIgnoreCase
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH:
|
|
||||||
return domain.SearchMethodStartsWith
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE:
|
|
||||||
return domain.SearchMethodStartsWithIgnoreCase
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS:
|
|
||||||
return domain.SearchMethodContains
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE:
|
|
||||||
return domain.SearchMethodContainsIgnoreCase
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH:
|
|
||||||
return domain.SearchMethodEndsWith
|
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE:
|
|
||||||
return domain.SearchMethodEndsWithIgnoreCase
|
|
||||||
default:
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TextMethodToQuery(method object_pb.TextQueryMethod) query.TextComparison {
|
func TextMethodToQuery(method object_pb.TextQueryMethod) query.TextComparison {
|
||||||
switch method {
|
switch method {
|
||||||
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS:
|
case object_pb.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS:
|
||||||
|
@ -52,7 +52,7 @@ func TestMain(m *testing.M) {
|
|||||||
func TestServer_GetAuthRequest(t *testing.T) {
|
func TestServer_GetAuthRequest(t *testing.T) {
|
||||||
project, err := Tester.CreateProject(CTX)
|
project, err := Tester.CreateProject(CTX)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
|
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -96,7 +96,7 @@ func TestServer_GetAuthRequest(t *testing.T) {
|
|||||||
func TestServer_CreateCallback(t *testing.T) {
|
func TestServer_CreateCallback(t *testing.T) {
|
||||||
project, err := Tester.CreateProject(CTX)
|
project, err := Tester.CreateProject(CTX)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionResp, err := Tester.Client.SessionV2.CreateSession(CTX, &session.CreateSessionRequest{
|
sessionResp, err := Tester.Client.SessionV2.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
Checks: &session.Checks{
|
Checks: &session.Checks{
|
||||||
|
@ -3,7 +3,6 @@ package project
|
|||||||
import (
|
import (
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
proj_model "github.com/zitadel/zitadel/internal/project/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
proj_pb "github.com/zitadel/zitadel/pkg/grpc/project"
|
proj_pb "github.com/zitadel/zitadel/pkg/grpc/project"
|
||||||
@ -112,45 +111,6 @@ func privateLabelingSettingToPb(setting domain.PrivateLabelingSetting) proj_pb.P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func grantedProjectStateToPb(state proj_model.ProjectState) proj_pb.ProjectGrantState {
|
|
||||||
switch state {
|
|
||||||
case proj_model.ProjectStateActive:
|
|
||||||
return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_ACTIVE
|
|
||||||
case proj_model.ProjectStateInactive:
|
|
||||||
return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_INACTIVE
|
|
||||||
default:
|
|
||||||
return proj_pb.ProjectGrantState_PROJECT_GRANT_STATE_UNSPECIFIED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GrantedProjectQueriesToModel(queries []*proj_pb.ProjectQuery) (_ []*proj_model.ProjectGrantViewSearchQuery, err error) {
|
|
||||||
q := make([]*proj_model.ProjectGrantViewSearchQuery, len(queries))
|
|
||||||
for i, query := range queries {
|
|
||||||
q[i], err = GrantedProjectQueryToModel(query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return q, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GrantedProjectQueryToModel(query *proj_pb.ProjectQuery) (*proj_model.ProjectGrantViewSearchQuery, error) {
|
|
||||||
switch q := query.Query.(type) {
|
|
||||||
case *proj_pb.ProjectQuery_NameQuery:
|
|
||||||
return GrantedProjectQueryNameToModel(q.NameQuery), nil
|
|
||||||
default:
|
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-Ags42", "List.Query.Invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GrantedProjectQueryNameToModel(query *proj_pb.ProjectNameQuery) *proj_model.ProjectGrantViewSearchQuery {
|
|
||||||
return &proj_model.ProjectGrantViewSearchQuery{
|
|
||||||
Key: proj_model.GrantedProjectSearchKeyName,
|
|
||||||
Method: object.TextMethodToModel(query.Method),
|
|
||||||
Value: query.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RoleQueriesToModel(queries []*proj_pb.RoleQuery) (_ []query.SearchQuery, err error) {
|
func RoleQueriesToModel(queries []*proj_pb.RoleQuery) (_ []query.SearchQuery, err error) {
|
||||||
q := make([]query.SearchQuery, len(queries))
|
q := make([]query.SearchQuery, len(queries))
|
||||||
for i, query := range queries {
|
for i, query := range queries {
|
||||||
|
@ -136,6 +136,20 @@ func (c *Client) IDTokenUserinfoClaimsAssertion() bool {
|
|||||||
return c.client.IDTokenUserinfoAssertion
|
return c.client.IDTokenUserinfoAssertion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) RedirectURIGlobs() []string {
|
||||||
|
if c.DevMode() {
|
||||||
|
return c.RedirectURIs()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) PostLogoutRedirectURIGlobs() []string {
|
||||||
|
if c.DevMode() {
|
||||||
|
return c.PostLogoutRedirectURIs()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func accessTokenTypeToOIDC(tokenType domain.OIDCTokenType) op.AccessTokenType {
|
func accessTokenTypeToOIDC(tokenType domain.OIDCTokenType) op.AccessTokenType {
|
||||||
switch tokenType {
|
switch tokenType {
|
||||||
case domain.OIDCTokenTypeBearer:
|
case domain.OIDCTokenTypeBearer:
|
||||||
|
@ -59,48 +59,118 @@ func TestOPStorage_SetUserinfoFromToken(t *testing.T) {
|
|||||||
func TestServer_Introspect(t *testing.T) {
|
func TestServer_Introspect(t *testing.T) {
|
||||||
project, err := Tester.CreateProject(CTX)
|
project, err := Tester.CreateProject(CTX)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||||
require.NoError(t, err)
|
|
||||||
api, err := Tester.CreateAPIClient(CTX, project.GetId())
|
|
||||||
require.NoError(t, err)
|
|
||||||
keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{
|
|
||||||
ProjectId: project.GetId(),
|
|
||||||
AppId: api.GetAppId(),
|
|
||||||
Type: authn.KeyType_KEY_TYPE_JSON,
|
|
||||||
ExpirationDate: nil,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
resourceServer, err := Tester.CreateResourceServer(CTX, keyResp.GetKeyDetails())
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess, oidc_api.ScopeResourceOwner}
|
wantAudience := []string{app.GetClientId(), project.GetId()}
|
||||||
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
tests := []struct {
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
name string
|
||||||
AuthRequestId: authRequestID,
|
api func(*testing.T) (apiID string, resourceServer rs.ResourceServer)
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
wantErr bool
|
||||||
Session: &oidc_pb.Session{
|
}{
|
||||||
SessionId: sessionID,
|
{
|
||||||
SessionToken: sessionToken,
|
name: "client assertion",
|
||||||
|
api: func(t *testing.T) (string, rs.ResourceServer) {
|
||||||
|
api, err := Tester.CreateAPIClientJWT(CTX, project.GetId())
|
||||||
|
require.NoError(t, err)
|
||||||
|
keyResp, err := Tester.Client.Mgmt.AddAppKey(CTX, &management.AddAppKeyRequest{
|
||||||
|
ProjectId: project.GetId(),
|
||||||
|
AppId: api.GetAppId(),
|
||||||
|
Type: authn.KeyType_KEY_TYPE_JSON,
|
||||||
|
ExpirationDate: nil,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
resourceServer, err := Tester.CreateResourceServerJWTProfile(CTX, keyResp.GetKeyDetails())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return api.GetClientId(), resourceServer
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
{
|
||||||
require.NoError(t, err)
|
name: "client credentials",
|
||||||
|
api: func(t *testing.T) (string, rs.ResourceServer) {
|
||||||
|
api, err := Tester.CreateAPIClientBasic(CTX, project.GetId())
|
||||||
|
require.NoError(t, err)
|
||||||
|
resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), api.GetClientSecret())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return api.GetClientId(), resourceServer
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "client invalid id, error",
|
||||||
|
api: func(t *testing.T) (string, rs.ResourceServer) {
|
||||||
|
api, err := Tester.CreateAPIClientBasic(CTX, project.GetId())
|
||||||
|
require.NoError(t, err)
|
||||||
|
resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, "xxxxx", api.GetClientSecret())
|
||||||
|
require.NoError(t, err)
|
||||||
|
return api.GetClientId(), resourceServer
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "client invalid secret, error",
|
||||||
|
api: func(t *testing.T) (string, rs.ResourceServer) {
|
||||||
|
api, err := Tester.CreateAPIClientBasic(CTX, project.GetId())
|
||||||
|
require.NoError(t, err)
|
||||||
|
resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), "xxxxx")
|
||||||
|
require.NoError(t, err)
|
||||||
|
return api.GetClientId(), resourceServer
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "client credentials on jwt client, error",
|
||||||
|
api: func(t *testing.T) (string, rs.ResourceServer) {
|
||||||
|
api, err := Tester.CreateAPIClientJWT(CTX, project.GetId())
|
||||||
|
require.NoError(t, err)
|
||||||
|
resourceServer, err := Tester.CreateResourceServerClientCredentials(CTX, api.GetClientId(), "xxxxx")
|
||||||
|
require.NoError(t, err)
|
||||||
|
return api.GetClientId(), resourceServer
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
apiID, resourceServer := tt.api(t)
|
||||||
|
// wantAudience grows for every API we add to the project.
|
||||||
|
wantAudience = append(wantAudience, apiID)
|
||||||
|
|
||||||
// code exchange
|
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess, oidc_api.ScopeResourceOwner}
|
||||||
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
|
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
||||||
tokens, err := exchangeTokens(t, app.GetClientId(), code)
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
require.NoError(t, err)
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
assertTokens(t, tokens, true)
|
AuthRequestId: authRequestID,
|
||||||
assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime)
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
|
Session: &oidc_pb.Session{
|
||||||
|
SessionId: sessionID,
|
||||||
|
SessionToken: sessionToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// test actual introspection
|
// code exchange
|
||||||
introspection, err := rs.Introspect[*oidc.IntrospectionResponse](context.Background(), resourceServer, tokens.AccessToken)
|
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
|
||||||
require.NoError(t, err)
|
tokens, err := exchangeTokens(t, app.GetClientId(), code)
|
||||||
assertIntrospection(t, introspection,
|
require.NoError(t, err)
|
||||||
Tester.OIDCIssuer(), app.GetClientId(),
|
assertTokens(t, tokens, true)
|
||||||
scope, []string{app.GetClientId(), api.GetClientId(), project.GetId()},
|
assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime)
|
||||||
tokens.Expiry, tokens.Expiry.Add(-12*time.Hour))
|
|
||||||
|
// test actual introspection
|
||||||
|
introspection, err := rs.Introspect[*oidc.IntrospectionResponse](context.Background(), resourceServer, tokens.AccessToken)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertIntrospection(t, introspection,
|
||||||
|
Tester.OIDCIssuer(), app.GetClientId(),
|
||||||
|
scope, wantAudience,
|
||||||
|
tokens.Expiry, tokens.Expiry.Add(-12*time.Hour))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertUserinfo(t *testing.T, userinfo *oidc.UserInfo) {
|
func assertUserinfo(t *testing.T, userinfo *oidc.UserInfo) {
|
||||||
@ -158,7 +228,7 @@ func TestServer_VerifyClient(t *testing.T) {
|
|||||||
|
|
||||||
inactiveClient, err := Tester.CreateOIDCInactivateClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
inactiveClient, err := Tester.CreateOIDCInactivateClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
nativeClient, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
nativeClient, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
basicWebClient, err := Tester.CreateOIDCWebClientBasic(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
basicWebClient, err := Tester.CreateOIDCWebClientBasic(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -72,7 +72,7 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// remaining errors shoudn't be returned to the client,
|
// remaining errors shouldn't be returned to the client,
|
||||||
// so we catch errors here, log them and return the response
|
// so we catch errors here, log them and return the response
|
||||||
// with active: false
|
// with active: false
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -122,6 +122,8 @@ type introspectionClientResult struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errNoClientSecret = errors.New("client has no configured secret")
|
||||||
|
|
||||||
func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCredentials, rc chan<- *introspectionClientResult) {
|
func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCredentials, rc chan<- *introspectionClientResult) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
|
|
||||||
@ -136,13 +138,16 @@ func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCrede
|
|||||||
if _, err := op.VerifyJWTAssertion(ctx, cc.ClientAssertion, verifier); err != nil {
|
if _, err := op.VerifyJWTAssertion(ctx, cc.ClientAssertion, verifier); err != nil {
|
||||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||||
}
|
}
|
||||||
} else {
|
return client.ClientID, client.ProjectID, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
if client.ClientSecret != nil {
|
||||||
if err := crypto.CompareHash(client.ClientSecret, []byte(cc.ClientSecret), s.hashAlg); err != nil {
|
if err := crypto.CompareHash(client.ClientSecret, []byte(cc.ClientSecret), s.hashAlg); err != nil {
|
||||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||||
}
|
}
|
||||||
|
return client.ClientID, client.ProjectID, nil
|
||||||
}
|
}
|
||||||
|
return "", "", oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret)
|
||||||
return client.ClientID, client.ProjectID, nil
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
span.EndWithError(err)
|
span.EndWithError(err)
|
||||||
|
@ -174,6 +174,40 @@ func Test_ZITADEL_API_success(t *testing.T) {
|
|||||||
require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId())
|
require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ZITADEL_API_glob_redirects(t *testing.T) {
|
||||||
|
const redirectURI = "https://my-org-1yfnjl2xj-my-app.vercel.app/api/auth/callback/zitadel"
|
||||||
|
clientID := createClientWithOpts(t, clientOpts{
|
||||||
|
redirectURI: "https://my-org-*-my-app.vercel.app/api/auth/callback/zitadel",
|
||||||
|
logoutURI: "https://my-org-*-my-app.vercel.app/",
|
||||||
|
devMode: true,
|
||||||
|
})
|
||||||
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope)
|
||||||
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
|
AuthRequestId: authRequestID,
|
||||||
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
|
Session: &oidc_pb.Session{
|
||||||
|
SessionId: sessionID,
|
||||||
|
SessionToken: sessionToken,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// code exchange
|
||||||
|
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
|
||||||
|
tokens, err := exchangeTokens(t, clientID, code)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assertTokens(t, tokens, false)
|
||||||
|
assertIDTokenClaims(t, tokens.IDTokenClaims, armPasskey, startTime, changeTime)
|
||||||
|
|
||||||
|
ctx := metadata.AppendToOutgoingContext(context.Background(), "Authorization", fmt.Sprintf("%s %s", tokens.TokenType, tokens.AccessToken))
|
||||||
|
|
||||||
|
myUserResp, err := Tester.Client.Auth.GetMyUser(ctx, &auth.GetMyUserRequest{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, User.GetUserId(), myUserResp.GetUser().GetId())
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ZITADEL_API_inactive_access_token(t *testing.T) {
|
func Test_ZITADEL_API_inactive_access_token(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
||||||
@ -257,9 +291,23 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createClient(t testing.TB) string {
|
func createClient(t testing.TB) string {
|
||||||
|
return createClientWithOpts(t, clientOpts{
|
||||||
|
redirectURI: redirectURI,
|
||||||
|
logoutURI: logoutRedirectURI,
|
||||||
|
devMode: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientOpts struct {
|
||||||
|
redirectURI string
|
||||||
|
logoutURI string
|
||||||
|
devMode bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func createClientWithOpts(t testing.TB, opts clientOpts) string {
|
||||||
project, err := Tester.CreateProject(CTX)
|
project, err := Tester.CreateProject(CTX)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
app, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
|
app, err := Tester.CreateOIDCNativeClient(CTX, opts.redirectURI, opts.logoutURI, project.GetId(), opts.devMode)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return app.GetClientId()
|
return app.GetClientId()
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,3 @@ func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_mode
|
|||||||
}
|
}
|
||||||
return model.UserSessionsToModel(userSessions), nil
|
return model.UserSessionsToModel(userSessions), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *UserSessionRepo) ActiveUserSessionCount() int64 {
|
|
||||||
userSessions, _ := repo.View.ActiveUserSessionsCount()
|
|
||||||
return int64(userSessions)
|
|
||||||
}
|
|
||||||
|
@ -8,5 +8,4 @@ import (
|
|||||||
|
|
||||||
type UserSessionRepository interface {
|
type UserSessionRepository interface {
|
||||||
GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error)
|
GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error)
|
||||||
ActiveUserSessionCount() int64
|
|
||||||
}
|
}
|
||||||
|
223
internal/cache/bigcache/bigcache_test.go
vendored
223
internal/cache/bigcache/bigcache_test.go
vendored
@ -1,223 +0,0 @@
|
|||||||
package bigcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
a_cache "github.com/allegro/bigcache"
|
|
||||||
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestStruct struct {
|
|
||||||
Test string
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBigCacheMock() *Bigcache {
|
|
||||||
cache, _ := a_cache.NewBigCache(a_cache.DefaultConfig(2000))
|
|
||||||
return &Bigcache{cache: cache}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
cache *Bigcache
|
|
||||||
key string
|
|
||||||
value *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "set cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "KEY",
|
|
||||||
value: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
result: &TestStruct{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "key empty",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "",
|
|
||||||
value: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "set cache nil value",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "KEY",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set(tt.args.key, tt.args.value)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil {
|
|
||||||
tt.args.cache.Get(tt.args.key, tt.res.result)
|
|
||||||
if tt.res.result == nil {
|
|
||||||
t.Errorf("got wrong result should get result: %v ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
event []*es_models.Event
|
|
||||||
cache *Bigcache
|
|
||||||
key string
|
|
||||||
setValue *TestStruct
|
|
||||||
getValue *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "get cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
result: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no key",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no value",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set("KEY", tt.args.setValue)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("something went wrong")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tt.args.cache.Get(tt.args.key, tt.args.getValue)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && !reflect.DeepEqual(tt.args.getValue, tt.res.result) {
|
|
||||||
t.Errorf("got wrong result expected: %v actual: %v", tt.res.result, tt.args.getValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDelete(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
event []*es_models.Event
|
|
||||||
cache *Bigcache
|
|
||||||
key string
|
|
||||||
setValue *TestStruct
|
|
||||||
getValue *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "delete cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no key",
|
|
||||||
args: args{
|
|
||||||
cache: getBigCacheMock(),
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set("KEY", tt.args.setValue)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("something went wrong")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tt.args.cache.Delete(tt.args.key)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
67
internal/cache/bigcache/cache.go
vendored
67
internal/cache/bigcache/cache.go
vendored
@ -1,67 +0,0 @@
|
|||||||
package bigcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
a_cache "github.com/allegro/bigcache"
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Bigcache struct {
|
|
||||||
cache *a_cache.BigCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBigcache(c *Config) (*Bigcache, error) {
|
|
||||||
cacheConfig := a_cache.DefaultConfig(c.CacheLifetime)
|
|
||||||
cacheConfig.HardMaxCacheSize = c.MaxCacheSizeInMB
|
|
||||||
cache, err := a_cache.NewBigCache(cacheConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Bigcache{
|
|
||||||
cache: cache,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Bigcache) Set(key string, object interface{}) error {
|
|
||||||
if key == "" || reflect.ValueOf(object).IsNil() {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "BIGCA-du73s", "key or value should not be empty")
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
enc := gob.NewEncoder(&b)
|
|
||||||
if err := enc.Encode(object); err != nil {
|
|
||||||
return zerrors.ThrowInvalidArgument(err, "BIGCA-RUyxI", "unable to encode object")
|
|
||||||
}
|
|
||||||
return c.cache.Set(key, b.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Bigcache) Get(key string, ptrToObject interface{}) error {
|
|
||||||
if key == "" || reflect.ValueOf(ptrToObject).IsNil() {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "BIGCA-dksoe", "key or value should not be empty")
|
|
||||||
}
|
|
||||||
value, err := c.cache.Get(key)
|
|
||||||
if err == a_cache.ErrEntryNotFound {
|
|
||||||
return zerrors.ThrowNotFound(err, "BIGCA-we32s", "not in cache")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("BIGCA-ftofbc").WithError(err).Info("read from cache failed")
|
|
||||||
return zerrors.ThrowInvalidArgument(err, "BIGCA-3idls", "error in reading from cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
b := bytes.NewBuffer(value)
|
|
||||||
dec := gob.NewDecoder(b)
|
|
||||||
|
|
||||||
return dec.Decode(ptrToObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Bigcache) Delete(key string) error {
|
|
||||||
if key == "" {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "BIGCA-clsi2", "key should not be empty")
|
|
||||||
}
|
|
||||||
return c.cache.Delete(key)
|
|
||||||
}
|
|
17
internal/cache/bigcache/config.go
vendored
17
internal/cache/bigcache/config.go
vendored
@ -1,17 +0,0 @@
|
|||||||
package bigcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/cache"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
MaxCacheSizeInMB int
|
|
||||||
//CacheLifetime if set, entries older than the lifetime will be deleted on cleanup (every minute)
|
|
||||||
CacheLifetime time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) NewCache() (cache.Cache, error) {
|
|
||||||
return NewBigcache(c)
|
|
||||||
}
|
|
7
internal/cache/cache.go
vendored
7
internal/cache/cache.go
vendored
@ -1,7 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
type Cache interface {
|
|
||||||
Set(key string, object interface{}) error
|
|
||||||
Get(key string, ptrToObject interface{}) error
|
|
||||||
Delete(key string) error
|
|
||||||
}
|
|
5
internal/cache/config.go
vendored
5
internal/cache/config.go
vendored
@ -1,5 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
type Config interface {
|
|
||||||
NewCache() (Cache, error)
|
|
||||||
}
|
|
59
internal/cache/config/config.go
vendored
59
internal/cache/config/config.go
vendored
@ -1,59 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/cache"
|
|
||||||
"github.com/zitadel/zitadel/internal/cache/bigcache"
|
|
||||||
"github.com/zitadel/zitadel/internal/cache/fastcache"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CacheConfig struct {
|
|
||||||
Type string
|
|
||||||
Config cache.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
var caches = map[string]func() cache.Config{
|
|
||||||
"bigcache": func() cache.Config { return &bigcache.Config{} },
|
|
||||||
"fastcache": func() cache.Config { return &fastcache.Config{} },
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CacheConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
var rc struct {
|
|
||||||
Type string
|
|
||||||
Config json.RawMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &rc); err != nil {
|
|
||||||
return zerrors.ThrowInternal(err, "CONFI-98ejs", "unable to unmarshal config")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type = rc.Type
|
|
||||||
|
|
||||||
var err error
|
|
||||||
c.Config, err = newCacheConfig(c.Type, rc.Config)
|
|
||||||
if err != nil {
|
|
||||||
return zerrors.ThrowInternal(err, "CONFI-do9es", "unable create config")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCacheConfig(cacheType string, configData []byte) (cache.Config, error) {
|
|
||||||
t, ok := caches[cacheType]
|
|
||||||
if !ok {
|
|
||||||
return nil, zerrors.ThrowInternal(nil, "CONFI-di328s", "no config")
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheConfig := t()
|
|
||||||
if len(configData) == 0 {
|
|
||||||
return cacheConfig, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.Unmarshal(configData, cacheConfig); err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(nil, "CONFI-skei3", "could not read config")
|
|
||||||
}
|
|
||||||
|
|
||||||
return cacheConfig, nil
|
|
||||||
}
|
|
11
internal/cache/fastcache/config.go
vendored
11
internal/cache/fastcache/config.go
vendored
@ -1,11 +0,0 @@
|
|||||||
package fastcache
|
|
||||||
|
|
||||||
import "github.com/zitadel/zitadel/internal/cache"
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
MaxCacheSizeInByte int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) NewCache() (cache.Cache, error) {
|
|
||||||
return NewFastcache(c)
|
|
||||||
}
|
|
57
internal/cache/fastcache/fastcache.go
vendored
57
internal/cache/fastcache/fastcache.go
vendored
@ -1,57 +0,0 @@
|
|||||||
package fastcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Fastcache struct {
|
|
||||||
cache *fastcache.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFastcache(config *Config) (*Fastcache, error) {
|
|
||||||
return &Fastcache{
|
|
||||||
cache: fastcache.New(config.MaxCacheSizeInByte),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fc *Fastcache) Set(key string, object interface{}) error {
|
|
||||||
if key == "" || reflect.ValueOf(object).IsNil() {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "FASTC-87dj3", "key or value should not be empty")
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
enc := gob.NewEncoder(&b)
|
|
||||||
if err := enc.Encode(object); err != nil {
|
|
||||||
return zerrors.ThrowInvalidArgument(err, "FASTC-RUyxI", "unable to encode object")
|
|
||||||
}
|
|
||||||
fc.cache.Set([]byte(key), b.Bytes())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fc *Fastcache) Get(key string, ptrToObject interface{}) error {
|
|
||||||
if key == "" || reflect.ValueOf(ptrToObject).IsNil() {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "FASTC-di8es", "key or value should not be empty")
|
|
||||||
}
|
|
||||||
data := fc.cache.Get(nil, []byte(key))
|
|
||||||
if len(data) == 0 {
|
|
||||||
return zerrors.ThrowNotFound(nil, "FASTC-xYzSm", "key not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
b := bytes.NewBuffer(data)
|
|
||||||
dec := gob.NewDecoder(b)
|
|
||||||
|
|
||||||
return dec.Decode(ptrToObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fc *Fastcache) Delete(key string) error {
|
|
||||||
if key == "" {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "FASTC-lod92", "key should not be empty")
|
|
||||||
}
|
|
||||||
fc.cache.Del([]byte(key))
|
|
||||||
return nil
|
|
||||||
}
|
|
218
internal/cache/fastcache/fastcache_test.go
vendored
218
internal/cache/fastcache/fastcache_test.go
vendored
@ -1,218 +0,0 @@
|
|||||||
package fastcache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
|
||||||
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestStruct struct {
|
|
||||||
Test string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
cache *Fastcache
|
|
||||||
key string
|
|
||||||
value *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "set cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "KEY",
|
|
||||||
value: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
result: &TestStruct{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "key empty",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "",
|
|
||||||
value: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "set cache nil value",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "KEY",
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set(tt.args.key, tt.args.value)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil {
|
|
||||||
tt.args.cache.Get(tt.args.key, tt.res.result)
|
|
||||||
if tt.res.result == nil {
|
|
||||||
t.Errorf("got wrong result should get result: %v ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
event []*es_models.Event
|
|
||||||
cache *Fastcache
|
|
||||||
key string
|
|
||||||
setValue *TestStruct
|
|
||||||
getValue *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "get cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
result: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no key",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no value",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set("KEY", tt.args.setValue)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("something went wrong")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tt.args.cache.Get(tt.args.key, tt.args.getValue)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && !reflect.DeepEqual(tt.args.getValue, tt.res.result) {
|
|
||||||
t.Errorf("got wrong result expected: %v actual: %v", tt.res.result, tt.args.getValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDelete(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
event []*es_models.Event
|
|
||||||
cache *Fastcache
|
|
||||||
key string
|
|
||||||
setValue *TestStruct
|
|
||||||
getValue *TestStruct
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
result *TestStruct
|
|
||||||
errFunc func(err error) bool
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "delete cache no err",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
key: "KEY",
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "get cache no key",
|
|
||||||
args: args{
|
|
||||||
cache: &Fastcache{cache: fastcache.New(2000)},
|
|
||||||
setValue: &TestStruct{Test: "Test"},
|
|
||||||
getValue: &TestStruct{Test: "Test"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
errFunc: zerrors.IsErrorInvalidArgument,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
err := tt.args.cache.Set("KEY", tt.args.setValue)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("something went wrong")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tt.args.cache.Delete(tt.args.key)
|
|
||||||
|
|
||||||
if tt.res.errFunc == nil && err != nil {
|
|
||||||
t.Errorf("got wrong result should not get err: %v ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
|
||||||
t.Errorf("got wrong err: %v ", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
3
internal/cache/generate.go
vendored
3
internal/cache/generate.go
vendored
@ -1,3 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
//go:generate mockgen -package mock -destination ./mock/cache.mock.go github.com/zitadel/zitadel/internal/cache Cache
|
|
80
internal/cache/mock/cache.mock.go
vendored
80
internal/cache/mock/cache.mock.go
vendored
@ -1,80 +0,0 @@
|
|||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: github.com/zitadel/zitadel/internal/cache (interfaces: Cache)
|
|
||||||
//
|
|
||||||
// Generated by this command:
|
|
||||||
//
|
|
||||||
// mockgen -package mock -destination ./mock/cache.mock.go github.com/zitadel/zitadel/internal/cache Cache
|
|
||||||
//
|
|
||||||
// Package mock is a generated GoMock package.
|
|
||||||
package mock
|
|
||||||
|
|
||||||
import (
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
gomock "go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockCache is a mock of Cache interface.
|
|
||||||
type MockCache struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockCacheMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockCacheMockRecorder is the mock recorder for MockCache.
|
|
||||||
type MockCacheMockRecorder struct {
|
|
||||||
mock *MockCache
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockCache creates a new mock instance.
|
|
||||||
func NewMockCache(ctrl *gomock.Controller) *MockCache {
|
|
||||||
mock := &MockCache{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockCacheMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockCache) EXPECT() *MockCacheMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete mocks base method.
|
|
||||||
func (m *MockCache) Delete(arg0 string) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Delete", arg0)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete indicates an expected call of Delete.
|
|
||||||
func (mr *MockCacheMockRecorder) Delete(arg0 any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockCache)(nil).Delete), arg0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get mocks base method.
|
|
||||||
func (m *MockCache) Get(arg0 string, arg1 any) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Get", arg0, arg1)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get indicates an expected call of Get.
|
|
||||||
func (mr *MockCacheMockRecorder) Get(arg0, arg1 any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockCache)(nil).Get), arg0, arg1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set mocks base method.
|
|
||||||
func (m *MockCache) Set(arg0 string, arg1 any) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Set", arg0, arg1)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set indicates an expected call of Set.
|
|
||||||
func (mr *MockCacheMockRecorder) Set(arg0, arg1 any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockCache)(nil).Set), arg0, arg1)
|
|
||||||
}
|
|
@ -2,303 +2,8 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/member"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/org"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/policy"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/project"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/usergrant"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type UniqueConstraintReadModel struct {
|
|
||||||
eventstore.WriteModel
|
|
||||||
|
|
||||||
UniqueConstraints []*domain.UniqueConstraintMigration
|
|
||||||
commandProvider commandProvider
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
type commandProvider interface {
|
type commandProvider interface {
|
||||||
domainPolicyWriteModel(ctx context.Context, orgID string) (*PolicyDomainWriteModel, error)
|
domainPolicyWriteModel(ctx context.Context, orgID string) (*PolicyDomainWriteModel, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUniqueConstraintReadModel(ctx context.Context, provider commandProvider) *UniqueConstraintReadModel {
|
|
||||||
return &UniqueConstraintReadModel{
|
|
||||||
ctx: ctx,
|
|
||||||
commandProvider: provider,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) AppendEvents(events ...eventstore.Event) {
|
|
||||||
rm.WriteModel.AppendEvents(events...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) Reduce() error {
|
|
||||||
for _, event := range rm.Events {
|
|
||||||
switch e := event.(type) {
|
|
||||||
case *org.OrgAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name))
|
|
||||||
case *org.OrgChangedEvent:
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgNameUniqueConstraint(e.Name))
|
|
||||||
case *org.DomainVerifiedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.NewAddOrgDomainUniqueConstraint(e.Domain))
|
|
||||||
case *org.DomainRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, org.UniqueOrgDomain)
|
|
||||||
case *instance.IDPConfigAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *instance.IDPConfigChangedEvent:
|
|
||||||
if e.Name == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *instance.IDPConfigRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType)
|
|
||||||
case *org.IDPConfigAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *org.IDPConfigChangedEvent:
|
|
||||||
if e.Name == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *org.IDPConfigRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.ConfigID, idpconfig.UniqueIDPConfigNameType)
|
|
||||||
case *instance.MailTextAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language))
|
|
||||||
case *org.MailTextAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.Aggregate().ID, e.MailTextType, e.Language))
|
|
||||||
case *org.MailTextRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.MailTextType+e.Language, policy.UniqueMailText)
|
|
||||||
case *project.ProjectAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *project.ProjectChangeEvent:
|
|
||||||
if e.Name == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.NewAddProjectNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner))
|
|
||||||
case *project.ProjectRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, project.UniqueProjectnameType)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueAppNameType)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, member.UniqueMember)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueRoleType)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueGrantType)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, project.UniqueProjectGrantMemberType)
|
|
||||||
case *project.ApplicationAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID))
|
|
||||||
case *project.ApplicationChangedEvent:
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.Aggregate().ID))
|
|
||||||
case *project.SAMLConfigAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewAddSAMLConfigEntityIDUniqueConstraint(e.EntityID))
|
|
||||||
case *project.SAMLConfigChangedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.AppID, project.NewRemoveSAMLConfigEntityIDUniqueConstraint(e.EntityID))
|
|
||||||
case *project.ApplicationRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.AppID, project.UniqueAppNameType)
|
|
||||||
case *project.GrantAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID, project.NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.Aggregate().ID))
|
|
||||||
case *project.GrantRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID, project.UniqueGrantType)
|
|
||||||
case *project.GrantMemberAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.Aggregate().ID, e.UserID, e.GrantID))
|
|
||||||
case *project.GrantMemberRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
|
|
||||||
case *project.GrantMemberCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
|
|
||||||
case *project.RoleAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.Aggregate().ID))
|
|
||||||
case *project.RoleRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Key, project.UniqueRoleType)
|
|
||||||
case *user.HumanAddedEvent:
|
|
||||||
policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("COMMAND-0k9Gs").WithError(err).Error("could not read policy for human added event unique constraint")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
|
||||||
case *user.HumanRegisteredEvent:
|
|
||||||
policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("COMMAND-m9fod").WithError(err).Error("could not read policy for human registered event unique constraint")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
|
||||||
case *user.MachineAddedEvent:
|
|
||||||
policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("COMMAND-2n8vs").WithError(err).Error("could not read policy for machine added event unique constraint")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
|
||||||
case *user.UserRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.UniqueUsername)
|
|
||||||
rm.listRemoveUniqueConstraint(e.Aggregate().ID, user.UniqueUserIDPLinkType)
|
|
||||||
case *user.UsernameChangedEvent:
|
|
||||||
policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("COMMAND-5n8gk").WithError(err).Error("could not read policy for username changed event unique constraint")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
|
||||||
case *user.DomainClaimedEvent:
|
|
||||||
policy, err := rm.commandProvider.domainPolicyWriteModel(rm.ctx, e.Aggregate().ResourceOwner)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("COMMAND-xb8uf").WithError(err).Error("could not read policy for domain claimed event unique constraint")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rm.changeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, user.NewAddUsernameUniqueConstraint(e.UserName, e.Aggregate().ResourceOwner, policy.UserLoginMustBeDomain))
|
|
||||||
case *user.UserIDPLinkAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.NewAddUserIDPLinkUniqueConstraint(e.IDPConfigID, e.ExternalUserID))
|
|
||||||
case *user.UserIDPLinkRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
|
|
||||||
case *user.UserIDPLinkCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.IDPConfigID+e.ExternalUserID, user.UniqueUserIDPLinkType)
|
|
||||||
case *usergrant.UserGrantAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.NewAddUserGrantUniqueConstraint(e.Aggregate().ResourceOwner, e.UserID, e.ProjectID, e.ProjectGrantID))
|
|
||||||
case *usergrant.UserGrantRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant)
|
|
||||||
case *usergrant.UserGrantCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.Aggregate().ID, usergrant.UniqueUserGrant)
|
|
||||||
case *instance.MemberAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
|
|
||||||
case *instance.MemberRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
case *instance.MemberCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
case *org.MemberAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
|
|
||||||
case *org.MemberRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
case *org.MemberCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
case *project.MemberAddedEvent:
|
|
||||||
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
|
|
||||||
case *project.MemberRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
case *project.MemberCascadeRemovedEvent:
|
|
||||||
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rm.WriteModel.Reduce()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
|
|
||||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
|
||||||
AddQuery().AggregateTypes(
|
|
||||||
instance.AggregateType,
|
|
||||||
org.AggregateType,
|
|
||||||
project.AggregateType,
|
|
||||||
user.AggregateType,
|
|
||||||
usergrant.AggregateType).
|
|
||||||
EventTypes(
|
|
||||||
org.OrgAddedEventType,
|
|
||||||
org.OrgChangedEventType,
|
|
||||||
org.OrgDomainVerifiedEventType,
|
|
||||||
org.OrgDomainRemovedEventType,
|
|
||||||
instance.IDPConfigAddedEventType,
|
|
||||||
instance.IDPConfigChangedEventType,
|
|
||||||
instance.IDPConfigRemovedEventType,
|
|
||||||
org.IDPConfigAddedEventType,
|
|
||||||
org.IDPConfigChangedEventType,
|
|
||||||
org.IDPConfigRemovedEventType,
|
|
||||||
instance.MailTextAddedEventType,
|
|
||||||
org.MailTextAddedEventType,
|
|
||||||
org.MailTextRemovedEventType,
|
|
||||||
project.ProjectAddedType,
|
|
||||||
project.ProjectChangedType,
|
|
||||||
project.ProjectRemovedType,
|
|
||||||
project.ApplicationAddedType,
|
|
||||||
project.ApplicationChangedType,
|
|
||||||
project.ApplicationRemovedType,
|
|
||||||
project.GrantAddedType,
|
|
||||||
project.GrantRemovedType,
|
|
||||||
project.GrantMemberAddedType,
|
|
||||||
project.GrantMemberRemovedType,
|
|
||||||
project.GrantMemberCascadeRemovedType,
|
|
||||||
project.RoleAddedType,
|
|
||||||
project.RoleRemovedType,
|
|
||||||
user.UserV1AddedType,
|
|
||||||
user.UserV1RegisteredType,
|
|
||||||
user.HumanAddedType,
|
|
||||||
user.HumanRegisteredType,
|
|
||||||
user.MachineAddedEventType,
|
|
||||||
user.UserUserNameChangedType,
|
|
||||||
user.UserDomainClaimedType,
|
|
||||||
user.UserRemovedType,
|
|
||||||
user.UserIDPLinkAddedType,
|
|
||||||
user.UserIDPLinkRemovedType,
|
|
||||||
user.UserIDPLinkCascadeRemovedType,
|
|
||||||
usergrant.UserGrantAddedType,
|
|
||||||
usergrant.UserGrantRemovedType,
|
|
||||||
usergrant.UserGrantCascadeRemovedType,
|
|
||||||
instance.MemberAddedEventType,
|
|
||||||
instance.MemberRemovedEventType,
|
|
||||||
instance.MemberCascadeRemovedEventType,
|
|
||||||
org.MemberAddedEventType,
|
|
||||||
org.MemberRemovedEventType,
|
|
||||||
org.MemberCascadeRemovedEventType,
|
|
||||||
project.MemberAddedType,
|
|
||||||
project.MemberRemovedType,
|
|
||||||
project.MemberCascadeRemovedType).
|
|
||||||
Builder()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) getUniqueConstraint(aggregateID, objectID, constraintType string) *domain.UniqueConstraintMigration {
|
|
||||||
for _, uniqueConstraint := range rm.UniqueConstraints {
|
|
||||||
if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType {
|
|
||||||
return uniqueConstraint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) addUniqueConstraint(aggregateID, objectID string, constraint *eventstore.UniqueConstraint) {
|
|
||||||
migrateUniqueConstraint := &domain.UniqueConstraintMigration{
|
|
||||||
AggregateID: aggregateID,
|
|
||||||
ObjectID: objectID,
|
|
||||||
UniqueType: constraint.UniqueType,
|
|
||||||
UniqueField: constraint.UniqueField,
|
|
||||||
ErrorMessage: constraint.ErrorMessage,
|
|
||||||
}
|
|
||||||
rm.UniqueConstraints = append(rm.UniqueConstraints, migrateUniqueConstraint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) changeUniqueConstraint(aggregateID, objectID string, constraint *eventstore.UniqueConstraint) {
|
|
||||||
for i, uniqueConstraint := range rm.UniqueConstraints {
|
|
||||||
if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraint.UniqueType {
|
|
||||||
rm.UniqueConstraints[i] = &domain.UniqueConstraintMigration{
|
|
||||||
AggregateID: aggregateID,
|
|
||||||
ObjectID: objectID,
|
|
||||||
UniqueType: constraint.UniqueType,
|
|
||||||
UniqueField: constraint.UniqueField,
|
|
||||||
ErrorMessage: constraint.ErrorMessage,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) removeUniqueConstraint(aggregateID, objectID, constraintType string) {
|
|
||||||
for i, uniqueConstraint := range rm.UniqueConstraints {
|
|
||||||
if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType {
|
|
||||||
copy(rm.UniqueConstraints[i:], rm.UniqueConstraints[i+1:])
|
|
||||||
rm.UniqueConstraints[len(rm.UniqueConstraints)-1] = nil
|
|
||||||
rm.UniqueConstraints = rm.UniqueConstraints[:len(rm.UniqueConstraints)-1]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rm *UniqueConstraintReadModel) listRemoveUniqueConstraint(aggregateID, constraintType string) {
|
|
||||||
for i := len(rm.UniqueConstraints) - 1; i >= 0; i-- {
|
|
||||||
if rm.UniqueConstraints[i].AggregateID == aggregateID && rm.UniqueConstraints[i].UniqueType == constraintType {
|
|
||||||
copy(rm.UniqueConstraints[i:], rm.UniqueConstraints[i+1:])
|
|
||||||
rm.UniqueConstraints[len(rm.UniqueConstraints)-1] = nil
|
|
||||||
rm.UniqueConstraints = rm.UniqueConstraints[:len(rm.UniqueConstraints)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/zitadel/logging"
|
"github.com/zitadel/logging"
|
||||||
@ -84,6 +85,7 @@ func (db *DB) QueryRowContext(ctx context.Context, scan func(row *sql.Row) error
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
row := tx.QueryRowContext(ctx, query, args...)
|
row := tx.QueryRowContext(ctx, query, args...)
|
||||||
|
logging.OnError(row.Err()).Error("unexpected query error")
|
||||||
|
|
||||||
err = scan(row)
|
err = scan(row)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -170,3 +172,9 @@ func (c Config) Password() string {
|
|||||||
func (c Config) Type() string {
|
func (c Config) Type() string {
|
||||||
return c.connector.Type()
|
return c.connector.Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EscapeLikeWildcards(value string) string {
|
||||||
|
value = strings.ReplaceAll(value, "%", "\\%")
|
||||||
|
value = strings.ReplaceAll(value, "_", "\\_")
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
@ -13,10 +13,6 @@ const (
|
|||||||
stateCount
|
stateCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f MFAState) Valid() bool {
|
|
||||||
return f >= 0 && f < stateCount
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultifactorConfigs struct {
|
type MultifactorConfigs struct {
|
||||||
OTP OTPConfig
|
OTP OTPConfig
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,6 @@ const (
|
|||||||
notificationCount
|
notificationCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f NotificationType) Valid() bool {
|
|
||||||
return f >= 0 && f < notificationCount
|
|
||||||
}
|
|
||||||
|
|
||||||
type NotificationProviderState int32
|
type NotificationProviderState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -10,10 +10,6 @@ const (
|
|||||||
policyStateCount
|
policyStateCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f PolicyState) Valid() bool {
|
|
||||||
return f >= 0 && f < policyStateCount
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s PolicyState) Exists() bool {
|
func (s PolicyState) Exists() bool {
|
||||||
return s != PolicyStateUnspecified && s != PolicyStateRemoved
|
return s != PolicyStateUnspecified && s != PolicyStateRemoved
|
||||||
}
|
}
|
||||||
|
@ -83,11 +83,3 @@ func (f LabelPolicy) IsValid() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f LabelPolicyState) Valid() bool {
|
|
||||||
return f >= 0 && f < labelPolicyStateCount
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s LabelPolicyState) Exists() bool {
|
|
||||||
return s != LabelPolicyStateUnspecified && s != LabelPolicyStateRemoved
|
|
||||||
}
|
|
||||||
|
@ -66,12 +66,6 @@ func (p IDPProvider) IsValid() bool {
|
|||||||
return p.IDPConfigID != ""
|
return p.IDPConfigID != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayName returns the name or a default
|
|
||||||
// to be used when always a name must be displayed (e.g. login)
|
|
||||||
func (p IDPProvider) DisplayName() string {
|
|
||||||
return IDPName(p.Name, p.IDPType)
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordlessType int32
|
type PasswordlessType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -88,7 +82,3 @@ func (f PasswordlessType) Valid() bool {
|
|||||||
func (p *LoginPolicy) HasSecondFactors() bool {
|
func (p *LoginPolicy) HasSecondFactors() bool {
|
||||||
return len(p.SecondFactors) > 0
|
return len(p.SecondFactors) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *LoginPolicy) HasMultiFactors() bool {
|
|
||||||
return len(p.MultiFactors) > 0
|
|
||||||
}
|
|
||||||
|
@ -11,11 +11,6 @@ type ProjectGrant struct {
|
|||||||
RoleKeys []string
|
RoleKeys []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectGrantIDs struct {
|
|
||||||
ProjectID string
|
|
||||||
GrantID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantState int32
|
type ProjectGrantState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -12,17 +12,6 @@ type ProjectGrantMember struct {
|
|||||||
Roles []string
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProjectGrantMember(aggregateID, userID, grantID string, roles ...string) *ProjectGrantMember {
|
|
||||||
return &ProjectGrantMember{
|
|
||||||
ObjectRoot: es_models.ObjectRoot{
|
|
||||||
AggregateID: aggregateID,
|
|
||||||
},
|
|
||||||
GrantID: grantID,
|
|
||||||
UserID: userID,
|
|
||||||
Roles: roles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *ProjectGrantMember) IsValid() bool {
|
func (i *ProjectGrantMember) IsValid() bool {
|
||||||
return i.AggregateID != "" && i.GrantID != "" && i.UserID != "" && len(i.Roles) != 0
|
return i.AggregateID != "" && i.GrantID != "" && i.UserID != "" && len(i.Roles) != 0
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,6 @@ const (
|
|||||||
identityProviderCount
|
identityProviderCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f IdentityProviderType) Valid() bool {
|
|
||||||
return f >= 0 && f < identityProviderCount
|
|
||||||
}
|
|
||||||
|
|
||||||
type IdentityProviderState int32
|
type IdentityProviderState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -22,7 +18,3 @@ const (
|
|||||||
|
|
||||||
idpProviderState
|
idpProviderState
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s IdentityProviderState) Valid() bool {
|
|
||||||
return s >= 0 && s < idpProviderState
|
|
||||||
}
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
type Step int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Step1 Step = iota + 1
|
|
||||||
Step2
|
|
||||||
Step3
|
|
||||||
Step4
|
|
||||||
Step5
|
|
||||||
Step6
|
|
||||||
Step7
|
|
||||||
Step8
|
|
||||||
Step9
|
|
||||||
Step10
|
|
||||||
Step11
|
|
||||||
Step12
|
|
||||||
Step13
|
|
||||||
Step14
|
|
||||||
Step15
|
|
||||||
Step16
|
|
||||||
Step17
|
|
||||||
Step18
|
|
||||||
Step19
|
|
||||||
Step20
|
|
||||||
Step21
|
|
||||||
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
|
|
||||||
StepCount
|
|
||||||
)
|
|
@ -1,9 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
type UniqueConstraintMigration struct {
|
|
||||||
AggregateID string
|
|
||||||
ObjectID string
|
|
||||||
UniqueType string
|
|
||||||
UniqueField string
|
|
||||||
ErrorMessage string
|
|
||||||
}
|
|
@ -1,10 +1,5 @@
|
|||||||
package domain
|
package domain
|
||||||
|
|
||||||
type User interface {
|
|
||||||
GetUsername() string
|
|
||||||
GetState() UserState
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserState int32
|
type UserState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -19,10 +14,6 @@ const (
|
|||||||
userStateCount
|
userStateCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f UserState) Valid() bool {
|
|
||||||
return f >= 0 && f < userStateCount
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s UserState) Exists() bool {
|
func (s UserState) Exists() bool {
|
||||||
return s != UserStateUnspecified && s != UserStateDeleted
|
return s != UserStateUnspecified && s != UserStateDeleted
|
||||||
}
|
}
|
||||||
@ -40,10 +31,6 @@ const (
|
|||||||
userTypeCount
|
userTypeCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f UserType) Valid() bool {
|
|
||||||
return f >= 0 && f < userTypeCount
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserAuthMethodType int32
|
type UserAuthMethodType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -58,10 +45,6 @@ const (
|
|||||||
userAuthMethodTypeCount
|
userAuthMethodTypeCount
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f UserAuthMethodType) Valid() bool {
|
|
||||||
return f >= 0 && f < userAuthMethodTypeCount
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasMFA checks whether the user authenticated with multiple auth factors.
|
// HasMFA checks whether the user authenticated with multiple auth factors.
|
||||||
// This can either be true if the list contains a [UserAuthMethodType] which by itself is MFA (e.g. [UserAuthMethodTypePasswordless])
|
// This can either be true if the list contains a [UserAuthMethodType] which by itself is MFA (e.g. [UserAuthMethodTypePasswordless])
|
||||||
// or if multiple factors were used (e.g. [UserAuthMethodTypePassword] and [UserAuthMethodTypeU2F])
|
// or if multiple factors were used (e.g. [UserAuthMethodTypePassword] and [UserAuthMethodTypeU2F])
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type UserMembership struct {
|
|
||||||
UserID string
|
|
||||||
MemberType MemberType
|
|
||||||
AggregateID string
|
|
||||||
//ObjectID differs from aggregate id if obejct is sub of an aggregate
|
|
||||||
ObjectID string
|
|
||||||
|
|
||||||
Roles []string
|
|
||||||
DisplayName string
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
ResourceOwner string
|
|
||||||
ResourceOwnerName string
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type MemberType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
MemberTypeUnspecified MemberType = iota
|
|
||||||
MemberTypeOrganisation
|
|
||||||
MemberTypeProject
|
|
||||||
MemberTypeProjectGrant
|
|
||||||
MemberTypeIam
|
|
||||||
)
|
|
@ -26,7 +26,7 @@ func latestSequences(ctx context.Context, tx *sql.Tx, commands []eventstore.Comm
|
|||||||
sequences := commandsToSequences(ctx, commands)
|
sequences := commandsToSequences(ctx, commands)
|
||||||
|
|
||||||
conditions, args := sequencesToSql(sequences)
|
conditions, args := sequencesToSql(sequences)
|
||||||
rows, err := tx.QueryContext(ctx, fmt.Sprintf(latestSequencesStmt, strings.Join(conditions, " OR ")), args...)
|
rows, err := tx.QueryContext(ctx, fmt.Sprintf(latestSequencesStmt, strings.Join(conditions, " UNION ALL ")), args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInternal(err, "V3-5jU5z", "Errors.Internal")
|
return nil, zerrors.ThrowInternal(err, "V3-5jU5z", "Errors.Internal")
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ func sequencesToSql(sequences []*latestSequence) (conditions []string, args []an
|
|||||||
conditions = make([]string, len(sequences))
|
conditions = make([]string, len(sequences))
|
||||||
|
|
||||||
for i, sequence := range sequences {
|
for i, sequence := range sequences {
|
||||||
conditions[i] = fmt.Sprintf("(instance_id = $%d AND aggregate_type = $%d AND aggregate_id = $%d)",
|
conditions[i] = fmt.Sprintf(`(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $%d AND aggregate_type = $%d AND aggregate_id = $%d ORDER BY "sequence" DESC LIMIT 1)`,
|
||||||
i*argsPerCondition+1,
|
i*argsPerCondition+1,
|
||||||
i*argsPerCondition+2,
|
i*argsPerCondition+2,
|
||||||
i*argsPerCondition+3,
|
i*argsPerCondition+3,
|
||||||
|
@ -247,7 +247,7 @@ func Test_sequencesToSql(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantConditions: []string{
|
wantConditions: []string{
|
||||||
"(instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3)",
|
`(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3 ORDER BY "sequence" DESC LIMIT 1)`,
|
||||||
},
|
},
|
||||||
wantArgs: []any{
|
wantArgs: []any{
|
||||||
"instance",
|
"instance",
|
||||||
@ -266,8 +266,8 @@ func Test_sequencesToSql(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantConditions: []string{
|
wantConditions: []string{
|
||||||
"(instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3)",
|
`(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $1 AND aggregate_type = $2 AND aggregate_id = $3 ORDER BY "sequence" DESC LIMIT 1)`,
|
||||||
"(instance_id = $4 AND aggregate_type = $5 AND aggregate_id = $6)",
|
`(SELECT instance_id, aggregate_type, aggregate_id, "sequence" FROM eventstore.events2 WHERE instance_id = $4 AND aggregate_type = $5 AND aggregate_id = $6 ORDER BY "sequence" DESC LIMIT 1)`,
|
||||||
},
|
},
|
||||||
wantArgs: []any{
|
wantArgs: []any{
|
||||||
"instance",
|
"instance",
|
||||||
|
@ -1,17 +1,5 @@
|
|||||||
with existing as (
|
WITH existing AS (
|
||||||
SELECT
|
%s
|
||||||
instance_id
|
|
||||||
, aggregate_type
|
|
||||||
, aggregate_id
|
|
||||||
, MAX("sequence") "sequence"
|
|
||||||
FROM
|
|
||||||
eventstore.events2 existing
|
|
||||||
WHERE
|
|
||||||
%s
|
|
||||||
GROUP BY
|
|
||||||
instance_id
|
|
||||||
, aggregate_type
|
|
||||||
, aggregate_id
|
|
||||||
) SELECT
|
) SELECT
|
||||||
e.instance_id
|
e.instance_id
|
||||||
, e.owner
|
, e.owner
|
||||||
@ -23,8 +11,8 @@ FROM
|
|||||||
JOIN
|
JOIN
|
||||||
existing
|
existing
|
||||||
ON
|
ON
|
||||||
e.instance_id = existing.instance_id
|
e.instance_id = existing.instance_id
|
||||||
AND e.aggregate_type = existing.aggregate_type
|
AND e.aggregate_type = existing.aggregate_type
|
||||||
AND e.aggregate_id = existing.aggregate_id
|
AND e.aggregate_id = existing.aggregate_id
|
||||||
AND e.sequence = existing.sequence
|
AND e.sequence = existing.sequence
|
||||||
FOR UPDATE;
|
FOR UPDATE;
|
@ -1,32 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Step int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Step1 Step = iota + 1
|
|
||||||
Step2
|
|
||||||
Step3
|
|
||||||
Step4
|
|
||||||
Step5
|
|
||||||
Step6
|
|
||||||
Step7
|
|
||||||
Step8
|
|
||||||
Step9
|
|
||||||
Step10
|
|
||||||
//StepCount marks the the length of possible steps (StepCount-1 == last possible step)
|
|
||||||
StepCount
|
|
||||||
)
|
|
||||||
|
|
||||||
type IAM struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
DefaultOrgID string
|
|
||||||
IAMProjectID string
|
|
||||||
SetUpDone domain.Step
|
|
||||||
SetUpStarted domain.Step
|
|
||||||
Members []*IAMMember
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
|
|
||||||
type IAMMember struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
|
|
||||||
UserID string
|
|
||||||
Roles []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewIAMMember(iamID, userID string) *IAMMember {
|
|
||||||
return &IAMMember{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, UserID: userID}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IAMMember) IsValid() bool {
|
|
||||||
return i.AggregateID != "" && i.UserID != "" && len(i.Roles) != 0
|
|
||||||
}
|
|
@ -1,110 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfig struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
IDPConfigID string
|
|
||||||
Type IdpConfigType
|
|
||||||
Name string
|
|
||||||
StylingType IDPStylingType
|
|
||||||
State IDPConfigState
|
|
||||||
OIDCConfig *OIDCIDPConfig
|
|
||||||
JWTIDPConfig *JWTIDPConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type OIDCIDPConfig struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
IDPConfigID string
|
|
||||||
ClientID string
|
|
||||||
ClientSecret *crypto.CryptoValue
|
|
||||||
ClientSecretString string
|
|
||||||
Issuer string
|
|
||||||
Scopes []string
|
|
||||||
IDPDisplayNameMapping OIDCMappingField
|
|
||||||
UsernameMapping OIDCMappingField
|
|
||||||
}
|
|
||||||
|
|
||||||
type JWTIDPConfig struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
IDPConfigID string
|
|
||||||
JWTEndpoint string
|
|
||||||
Issuer string
|
|
||||||
KeysEndpoint string
|
|
||||||
}
|
|
||||||
|
|
||||||
type IdpConfigType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPConfigTypeOIDC IdpConfigType = iota
|
|
||||||
IDPConfigTypeSAML
|
|
||||||
IDPConfigTypeJWT
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfigState int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPConfigStateActive IDPConfigState = iota
|
|
||||||
IDPConfigStateInactive
|
|
||||||
IDPConfigStateRemoved
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPStylingType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPStylingTypeUnspecified IDPStylingType = iota
|
|
||||||
IDPStylingTypeGoogle
|
|
||||||
)
|
|
||||||
|
|
||||||
type OIDCMappingField int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
OIDCMappingFieldUnspecified OIDCMappingField = iota
|
|
||||||
OIDCMappingFieldPreferredLoginName
|
|
||||||
OIDCMappingFieldEmail
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewIDPConfig(iamID, idpID string) *IDPConfig {
|
|
||||||
return &IDPConfig{ObjectRoot: es_models.ObjectRoot{AggregateID: iamID}, IDPConfigID: idpID}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (idp *IDPConfig) IsValid(includeConfig bool) bool {
|
|
||||||
if idp.Name == "" || idp.AggregateID == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !includeConfig {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if idp.Type == IDPConfigTypeOIDC && !idp.OIDCConfig.IsValid(true) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oi *OIDCIDPConfig) IsValid(withSecret bool) bool {
|
|
||||||
if withSecret {
|
|
||||||
return oi.ClientID != "" && oi.Issuer != "" && oi.ClientSecretString != ""
|
|
||||||
}
|
|
||||||
return oi.ClientID != "" && oi.Issuer != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oi *OIDCIDPConfig) CryptSecret(crypt crypto.Crypto) error {
|
|
||||||
cryptedSecret, err := crypto.Crypt([]byte(oi.ClientSecretString), crypt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
oi.ClientSecret = cryptedSecret
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st IDPStylingType) GetCSSClass() string {
|
|
||||||
switch st {
|
|
||||||
case IDPStylingTypeGoogle:
|
|
||||||
return "google"
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfigView struct {
|
|
||||||
AggregateID string
|
|
||||||
IDPConfigID string
|
|
||||||
Name string
|
|
||||||
StylingType IDPStylingType
|
|
||||||
AutoRegister bool
|
|
||||||
State IDPConfigState
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
IDPProviderType IDPProviderType
|
|
||||||
|
|
||||||
IsOIDC bool
|
|
||||||
OIDCClientID string
|
|
||||||
OIDCClientSecret *crypto.CryptoValue
|
|
||||||
OIDCIssuer string
|
|
||||||
OIDCScopes []string
|
|
||||||
OIDCIDPDisplayNameMapping OIDCMappingField
|
|
||||||
OIDCUsernameMapping OIDCMappingField
|
|
||||||
OAuthAuthorizationEndpoint string
|
|
||||||
OAuthTokenEndpoint string
|
|
||||||
JWTEndpoint string
|
|
||||||
JWTIssuer string
|
|
||||||
JWTKeysEndpoint string
|
|
||||||
JWTHeaderName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPConfigSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn IDPConfigSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*IDPConfigSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPConfigSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPConfigSearchKeyUnspecified IDPConfigSearchKey = iota
|
|
||||||
IDPConfigSearchKeyName
|
|
||||||
IDPConfigSearchKeyAggregateID
|
|
||||||
IDPConfigSearchKeyIdpConfigID
|
|
||||||
IDPConfigSearchKeyIdpProviderType
|
|
||||||
IDPConfigSearchKeyInstanceID
|
|
||||||
IDPConfigSearchKeyOwnerRemoved
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfigSearchQuery struct {
|
|
||||||
Key IDPConfigSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPConfigSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*IDPConfigView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPConfigSearchRequest) EnsureLimit(limit uint64) error {
|
|
||||||
if r.Limit > limit {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "SEARCH-Mv9sd", "Errors.Limit.ExceedsDefault")
|
|
||||||
}
|
|
||||||
if r.Limit == 0 {
|
|
||||||
r.Limit = limit
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPConfigSearchRequest) AppendMyOrgQuery(orgID, iamID string) {
|
|
||||||
r.Queries = append(r.Queries, &IDPConfigSearchQuery{Key: IDPConfigSearchKeyAggregateID, Method: domain.SearchMethodIsOneOf, Value: []string{orgID, iamID}})
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPProviderView struct {
|
|
||||||
AggregateID string
|
|
||||||
IDPConfigID string
|
|
||||||
IDPProviderType IDPProviderType
|
|
||||||
Name string
|
|
||||||
StylingType IDPStylingType
|
|
||||||
IDPConfigType IdpConfigType
|
|
||||||
IDPState IDPConfigState
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPProviderSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn IDPProviderSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*IDPProviderSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPProviderSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPProviderSearchKeyUnspecified IDPProviderSearchKey = iota
|
|
||||||
IDPProviderSearchKeyAggregateID
|
|
||||||
IDPProviderSearchKeyIdpConfigID
|
|
||||||
IDPProviderSearchKeyState
|
|
||||||
IDPProviderSearchKeyInstanceID
|
|
||||||
IDPProviderSearchKeyOwnerRemoved
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPProviderSearchQuery struct {
|
|
||||||
Key IDPProviderSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPProviderSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*IDPProviderView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPProviderSearchRequest) EnsureLimit(limit uint64) error {
|
|
||||||
if r.Limit > limit {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "SEARCH-3n8fs", "Errors.Limit.ExceedsDefault")
|
|
||||||
}
|
|
||||||
if r.Limit == 0 {
|
|
||||||
r.Limit = limit
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPProviderSearchRequest) AppendAggregateIDQuery(aggregateID string) {
|
|
||||||
r.Queries = append(r.Queries, &IDPProviderSearchQuery{Key: IDPProviderSearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID})
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LabelPolicy struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
Default bool
|
|
||||||
PrimaryColor string
|
|
||||||
BackgroundColor string
|
|
||||||
FontColor string
|
|
||||||
WarnColor string
|
|
||||||
PrimaryColorDark string
|
|
||||||
BackgroundColorDark string
|
|
||||||
FontColorDark string
|
|
||||||
WarnColorDark string
|
|
||||||
HideLoginNameSuffix bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LabelPolicy) IsValid() bool {
|
|
||||||
return p.ObjectRoot.AggregateID != ""
|
|
||||||
}
|
|
@ -1,47 +1,9 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LabelPolicyView struct {
|
|
||||||
AggregateID string
|
|
||||||
PrimaryColor string
|
|
||||||
BackgroundColor string
|
|
||||||
WarnColor string
|
|
||||||
FontColor string
|
|
||||||
LogoURL string
|
|
||||||
IconURL string
|
|
||||||
|
|
||||||
PrimaryColorDark string
|
|
||||||
BackgroundColorDark string
|
|
||||||
WarnColorDark string
|
|
||||||
FontColorDark string
|
|
||||||
LogoDarkURL string
|
|
||||||
IconDarkURL string
|
|
||||||
FontURL string
|
|
||||||
|
|
||||||
HideLoginNameSuffix bool
|
|
||||||
ErrorMsgPopup bool
|
|
||||||
DisableWatermark bool
|
|
||||||
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type LabelPolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn LabelPolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*LabelPolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type LabelPolicySearchKey int32
|
type LabelPolicySearchKey int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -57,12 +19,3 @@ type LabelPolicySearchQuery struct {
|
|||||||
Method domain.SearchMethod
|
Method domain.SearchMethod
|
||||||
Value interface{}
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LabelPolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*LabelPolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
@ -1,90 +1,8 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoginPolicy struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
Default bool
|
|
||||||
AllowUsernamePassword bool
|
|
||||||
AllowRegister bool
|
|
||||||
AllowExternalIdp bool
|
|
||||||
IDPProviders []*IDPProvider
|
|
||||||
ForceMFA bool
|
|
||||||
SecondFactors []domain.SecondFactorType
|
|
||||||
MultiFactors []domain.MultiFactorType
|
|
||||||
PasswordlessType PasswordlessType
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDPProvider struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
Type IDPProviderType
|
|
||||||
IDPConfigID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type PolicyState int32
|
type PolicyState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PolicyStateActive PolicyState = iota
|
PolicyStateActive PolicyState = iota
|
||||||
PolicyStateRemoved
|
PolicyStateRemoved
|
||||||
)
|
)
|
||||||
|
|
||||||
type IDPProviderType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPProviderTypeSystem IDPProviderType = iota
|
|
||||||
IDPProviderTypeOrg
|
|
||||||
)
|
|
||||||
|
|
||||||
type MultiFactorType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
MultiFactorTypeUnspecified MultiFactorType = iota
|
|
||||||
MultiFactorTypeU2FWithPIN
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordlessType int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PasswordlessTypeNotAllowed PasswordlessType = iota
|
|
||||||
PasswordlessTypeAllowed
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *LoginPolicy) IsValid() bool {
|
|
||||||
return p.ObjectRoot.AggregateID != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *IDPProvider) IsValid() bool {
|
|
||||||
return p.ObjectRoot.AggregateID != "" && p.IDPConfigID != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicy) GetIdpProvider(id string) (int, *IDPProvider) {
|
|
||||||
for i, m := range p.IDPProviders {
|
|
||||||
if m.IDPConfigID == id {
|
|
||||||
return i, m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicy) GetSecondFactor(mfaType domain.SecondFactorType) (int, domain.SecondFactorType) {
|
|
||||||
for i, m := range p.SecondFactors {
|
|
||||||
if m == mfaType {
|
|
||||||
return i, m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicy) GetMultiFactor(mfaType domain.MultiFactorType) (int, domain.MultiFactorType) {
|
|
||||||
for i, m := range p.MultiFactors {
|
|
||||||
if m == mfaType {
|
|
||||||
return i, m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, 0
|
|
||||||
}
|
|
||||||
|
@ -1,129 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoginPolicyView struct {
|
|
||||||
AggregateID string
|
|
||||||
AllowUsernamePassword bool
|
|
||||||
AllowRegister bool
|
|
||||||
AllowExternalIDP bool
|
|
||||||
ForceMFA bool
|
|
||||||
HidePasswordReset bool
|
|
||||||
PasswordlessType PasswordlessType
|
|
||||||
SecondFactors []domain.SecondFactorType
|
|
||||||
MultiFactors []domain.MultiFactorType
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginPolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn LoginPolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*LoginPolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginPolicySearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
LoginPolicySearchKeyUnspecified LoginPolicySearchKey = iota
|
|
||||||
LoginPolicySearchKeyAggregateID
|
|
||||||
LoginPolicySearchKeyDefault
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoginPolicySearchQuery struct {
|
|
||||||
Key LoginPolicySearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginPolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*LoginPolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicyView) HasSecondFactors() bool {
|
|
||||||
if p.SecondFactors == nil || len(p.SecondFactors) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicyView) HasMultiFactors() bool {
|
|
||||||
if p.MultiFactors == nil || len(p.MultiFactors) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *LoginPolicyView) ToLoginPolicyDomain() *domain.LoginPolicy {
|
|
||||||
return &domain.LoginPolicy{
|
|
||||||
ObjectRoot: models.ObjectRoot{
|
|
||||||
AggregateID: p.AggregateID,
|
|
||||||
CreationDate: p.CreationDate,
|
|
||||||
ChangeDate: p.ChangeDate,
|
|
||||||
Sequence: p.Sequence,
|
|
||||||
},
|
|
||||||
Default: p.Default,
|
|
||||||
AllowUsernamePassword: p.AllowUsernamePassword,
|
|
||||||
AllowRegister: p.AllowRegister,
|
|
||||||
AllowExternalIDP: p.AllowExternalIDP,
|
|
||||||
ForceMFA: p.ForceMFA,
|
|
||||||
HidePasswordReset: p.HidePasswordReset,
|
|
||||||
PasswordlessType: passwordLessTypeToDomain(p.PasswordlessType),
|
|
||||||
SecondFactors: secondFactorsToDomain(p.SecondFactors),
|
|
||||||
MultiFactors: multiFactorsToDomain(p.MultiFactors),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func passwordLessTypeToDomain(passwordless PasswordlessType) domain.PasswordlessType {
|
|
||||||
switch passwordless {
|
|
||||||
case PasswordlessTypeNotAllowed:
|
|
||||||
return domain.PasswordlessTypeNotAllowed
|
|
||||||
case PasswordlessTypeAllowed:
|
|
||||||
return domain.PasswordlessTypeAllowed
|
|
||||||
default:
|
|
||||||
return domain.PasswordlessTypeNotAllowed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func secondFactorsToDomain(types []domain.SecondFactorType) []domain.SecondFactorType {
|
|
||||||
secondfactors := make([]domain.SecondFactorType, len(types))
|
|
||||||
for i, secondfactorType := range types {
|
|
||||||
switch secondfactorType {
|
|
||||||
case domain.SecondFactorTypeU2F:
|
|
||||||
secondfactors[i] = domain.SecondFactorTypeU2F
|
|
||||||
case domain.SecondFactorTypeTOTP:
|
|
||||||
secondfactors[i] = domain.SecondFactorTypeTOTP
|
|
||||||
case domain.SecondFactorTypeOTPEmail:
|
|
||||||
secondfactors[i] = domain.SecondFactorTypeOTPEmail
|
|
||||||
case domain.SecondFactorTypeOTPSMS:
|
|
||||||
secondfactors[i] = domain.SecondFactorTypeOTPSMS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return secondfactors
|
|
||||||
}
|
|
||||||
|
|
||||||
func multiFactorsToDomain(types []domain.MultiFactorType) []domain.MultiFactorType {
|
|
||||||
multifactors := make([]domain.MultiFactorType, len(types))
|
|
||||||
for i, multifactorType := range types {
|
|
||||||
switch multifactorType {
|
|
||||||
case domain.MultiFactorTypeU2FWithPIN:
|
|
||||||
multifactors[i] = domain.MultiFactorTypeU2FWithPIN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return multifactors
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MailTemplate struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
Default bool
|
|
||||||
Template []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MailTemplate) IsValid() bool {
|
|
||||||
return p.ObjectRoot.AggregateID != ""
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MailTexts struct {
|
|
||||||
Texts []*MailText
|
|
||||||
Default bool
|
|
||||||
}
|
|
||||||
type MailText struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
Default bool
|
|
||||||
MailTextType string
|
|
||||||
Language string
|
|
||||||
Title string
|
|
||||||
PreHeader string
|
|
||||||
Subject string
|
|
||||||
Greeting string
|
|
||||||
Text string
|
|
||||||
ButtonText string
|
|
||||||
FooterText string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MailText) IsValid() bool {
|
|
||||||
return p.ObjectRoot.AggregateID != ""
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MessageTextView struct {
|
|
||||||
AggregateID string
|
|
||||||
MessageTextType string
|
|
||||||
Language language.Tag
|
|
||||||
Title string
|
|
||||||
PreHeader string
|
|
||||||
Subject string
|
|
||||||
Greeting string
|
|
||||||
Text string
|
|
||||||
ButtonText string
|
|
||||||
FooterText string
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageTextSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn MessageTextSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*MessageTextSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageTextSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
MessageTextSearchKeyUnspecified MessageTextSearchKey = iota
|
|
||||||
MessageTextSearchKeyAggregateID
|
|
||||||
MessageTextSearchKeyMessageTextType
|
|
||||||
MessageTextSearchKeyLanguage
|
|
||||||
)
|
|
||||||
|
|
||||||
type MessageTextSearchQuery struct {
|
|
||||||
Key MessageTextSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageTextSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*MessageTextView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SecondFactorsSearchRequest struct {
|
|
||||||
Queries []*MFASearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiFactorsSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
Asc bool
|
|
||||||
Queries []*MFASearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type MFASearchQuery struct {
|
|
||||||
Key MFASearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type MFASearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
MFASearchKeyUnspecified MFASearchKey = iota
|
|
||||||
MFASearchKeyAggregateID
|
|
||||||
)
|
|
||||||
|
|
||||||
type SecondFactorsSearchResponse struct {
|
|
||||||
TotalResult uint64
|
|
||||||
Result []domain.SecondFactorType
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiFactorsSearchResponse struct {
|
|
||||||
TotalResult uint64
|
|
||||||
Result []domain.MultiFactorType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *SecondFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) {
|
|
||||||
r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *MultiFactorsSearchRequest) AppendAggregateIDQuery(aggregateID string) {
|
|
||||||
r.Queries = append(r.Queries, &MFASearchQuery{Key: MFASearchKeyAggregateID, Method: domain.SearchMethodEquals, Value: aggregateID})
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordAgePolicy struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
MaxAgeDays uint64
|
|
||||||
ExpireWarnDays uint64
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordAgePolicyView struct {
|
|
||||||
AggregateID string
|
|
||||||
MaxAgeDays uint64
|
|
||||||
ExpireWarnDays uint64
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordAgePolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn PasswordAgePolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*PasswordAgePolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordAgePolicySearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PasswordAgePolicySearchKeyUnspecified PasswordAgePolicySearchKey = iota
|
|
||||||
PasswordAgePolicySearchKeyAggregateID
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordAgePolicySearchQuery struct {
|
|
||||||
Key PasswordAgePolicySearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordAgePolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*PasswordAgePolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
hasStringLowerCase = regexp.MustCompile(`[a-z]`).MatchString
|
|
||||||
hasStringUpperCase = regexp.MustCompile(`[A-Z]`).MatchString
|
|
||||||
hasNumber = regexp.MustCompile(`[0-9]`).MatchString
|
|
||||||
hasSymbol = regexp.MustCompile(`[^A-Za-z0-9]`).MatchString
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordComplexityPolicy struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
MinLength uint64
|
|
||||||
HasLowercase bool
|
|
||||||
HasUppercase bool
|
|
||||||
HasNumber bool
|
|
||||||
HasSymbol bool
|
|
||||||
|
|
||||||
Default bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PasswordComplexityPolicy) IsValid() error {
|
|
||||||
if p.MinLength == 0 || p.MinLength > 72 {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-Lsp0e", "Errors.User.PasswordComplexityPolicy.MinLengthNotAllowed")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PasswordComplexityPolicy) Check(password string) error {
|
|
||||||
if p.MinLength != 0 && uint64(len(password)) < p.MinLength {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-HuJf6", "Errors.User.PasswordComplexityPolicy.MinLength")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.HasLowercase && !hasStringLowerCase(password) {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-co3Xw", "Errors.User.PasswordComplexityPolicy.HasLower")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.HasUppercase && !hasStringUpperCase(password) {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-VoaRj", "Errors.User.PasswordComplexityPolicy.HasUpper")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.HasNumber && !hasNumber(password) {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-ZBv4H", "Errors.User.PasswordComplexityPolicy.HasNumber")
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.HasSymbol && !hasSymbol(password) {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "MODEL-ZDLwA", "Errors.User.PasswordComplexityPolicy.HasSymbol")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -2,8 +2,6 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PasswordComplexityPolicyView struct {
|
type PasswordComplexityPolicyView struct {
|
||||||
@ -19,33 +17,3 @@ type PasswordComplexityPolicyView struct {
|
|||||||
ChangeDate time.Time
|
ChangeDate time.Time
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PasswordComplexityPolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn PasswordComplexityPolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*PasswordComplexityPolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordComplexityPolicySearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PasswordComplexityPolicySearchKeyUnspecified PasswordComplexityPolicySearchKey = iota
|
|
||||||
PasswordComplexityPolicySearchKeyAggregateID
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordComplexityPolicySearchQuery struct {
|
|
||||||
Key PasswordComplexityPolicySearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PasswordComplexityPolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*PasswordComplexityPolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LockoutPolicy struct {
|
|
||||||
models.ObjectRoot
|
|
||||||
|
|
||||||
State PolicyState
|
|
||||||
MaxPasswordAttempts uint64
|
|
||||||
ShowLockOutFailures bool
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LockoutPolicyView struct {
|
|
||||||
AggregateID string
|
|
||||||
MaxPasswordAttempts uint64
|
|
||||||
ShowLockOutFailures bool
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type LockoutPolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn LockoutPolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*LockoutPolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type LockoutPolicySearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
LockoutPolicySearchKeyUnspecified LockoutPolicySearchKey = iota
|
|
||||||
LockoutPolicySearchKeyAggregateID
|
|
||||||
)
|
|
||||||
|
|
||||||
type LockoutPolicySearchQuery struct {
|
|
||||||
Key LockoutPolicySearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type LockoutPolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*LockoutPolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PrivacyPolicyView struct {
|
|
||||||
AggregateID string
|
|
||||||
TOSLink string
|
|
||||||
PrivacyLink string
|
|
||||||
SupportEmail string
|
|
||||||
Default bool
|
|
||||||
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrivacyPolicySearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn PrivacyPolicySearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*PrivacyPolicySearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrivacyPolicySearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
PrivacyPolicySearchKeyUnspecified PrivacyPolicySearchKey = iota
|
|
||||||
PrivacyPolicySearchKeyAggregateID
|
|
||||||
)
|
|
||||||
|
|
||||||
type PrivacyPolicySearchQuery struct {
|
|
||||||
Key PrivacyPolicySearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrivacyPolicySearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*PrivacyPolicyView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IAMMember struct {
|
|
||||||
es_models.ObjectRoot
|
|
||||||
UserID string `json:"userId,omitempty"`
|
|
||||||
Roles []string `json:"roles,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *IAMMember) SetData(event *es_models.Event) error {
|
|
||||||
m.ObjectRoot.AppendEvent(event)
|
|
||||||
if err := json.Unmarshal(event.Data, m); err != nil {
|
|
||||||
logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -22,15 +22,6 @@ func DomainPolicyToModel(policy *DomainPolicy) *iam_model.DomainPolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DomainPolicy) Changes(changed *DomainPolicy) map[string]interface{} {
|
|
||||||
changes := make(map[string]interface{}, 1)
|
|
||||||
|
|
||||||
if p.UserLoginMustBeDomain != changed.UserLoginMustBeDomain {
|
|
||||||
changes["userLoginMustBeDomain"] = changed.UserLoginMustBeDomain
|
|
||||||
}
|
|
||||||
return changes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *DomainPolicy) SetData(event eventstore.Event) error {
|
func (p *DomainPolicy) SetData(event eventstore.Event) error {
|
||||||
err := event.Unmarshal(p)
|
err := event.Unmarshal(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOrgIAMPolicyChanges(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
existing *DomainPolicy
|
|
||||||
new *DomainPolicy
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
changesLen int
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "org iam policy all attributes change",
|
|
||||||
args: args{
|
|
||||||
existing: &DomainPolicy{UserLoginMustBeDomain: true},
|
|
||||||
new: &DomainPolicy{UserLoginMustBeDomain: false},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no changes",
|
|
||||||
args: args{
|
|
||||||
existing: &DomainPolicy{UserLoginMustBeDomain: true},
|
|
||||||
new: &DomainPolicy{UserLoginMustBeDomain: true},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
changes := tt.args.existing.Changes(tt.args.new)
|
|
||||||
if len(changes) != tt.res.changesLen {
|
|
||||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
package view
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/iam/repository/view/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/view/repository"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetIDPProviderByAggregateIDAndConfigID(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) (*model.IDPProviderView, error) {
|
|
||||||
policy := new(model.IDPProviderView)
|
|
||||||
aggIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyAggregateID, Value: aggregateID, Method: domain.SearchMethodEquals}
|
|
||||||
idpConfigIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyIdpConfigID, Value: idpConfigID, Method: domain.SearchMethodEquals}
|
|
||||||
instanceIDQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
|
||||||
ownerRemovedQuery := &model.IDPProviderSearchQuery{Key: iam_model.IDPProviderSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals}
|
|
||||||
query := repository.PrepareGetByQuery(table, aggIDQuery, idpConfigIDQuery, instanceIDQuery, ownerRemovedQuery)
|
|
||||||
err := query(db, policy)
|
|
||||||
if zerrors.IsNotFound(err) {
|
|
||||||
return nil, zerrors.ThrowNotFound(nil, "VIEW-Skvi8", "Errors.IAM.LoginPolicy.IDP.NotExisting")
|
|
||||||
}
|
|
||||||
return policy, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPProvidersByIdpConfigID(db *gorm.DB, table, idpConfigID, instanceID string) ([]*model.IDPProviderView, error) {
|
|
||||||
providers := make([]*model.IDPProviderView, 0)
|
|
||||||
queries := []*iam_model.IDPProviderSearchQuery{
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyIdpConfigID,
|
|
||||||
Value: idpConfigID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyInstanceID,
|
|
||||||
Value: instanceID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyOwnerRemoved,
|
|
||||||
Value: false,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
|
||||||
_, err := query(db, &providers)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return providers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPProvidersByAggregateIDAndState(db *gorm.DB, table string, aggregateID, instanceID string, idpConfigState iam_model.IDPConfigState) ([]*model.IDPProviderView, error) {
|
|
||||||
providers := make([]*model.IDPProviderView, 0)
|
|
||||||
queries := []*iam_model.IDPProviderSearchQuery{
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyAggregateID,
|
|
||||||
Value: aggregateID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyState,
|
|
||||||
Value: int(idpConfigState),
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyInstanceID,
|
|
||||||
Value: instanceID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPProviderSearchKeyOwnerRemoved,
|
|
||||||
Value: false,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Queries: queries})
|
|
||||||
_, err := query(db, &providers)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return providers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SearchIDPProviders(db *gorm.DB, table string, req *iam_model.IDPProviderSearchRequest) ([]*model.IDPProviderView, uint64, error) {
|
|
||||||
providers := make([]*model.IDPProviderView, 0)
|
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPProviderSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
|
||||||
count, err := query(db, &providers)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
return providers, count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutIDPProvider(db *gorm.DB, table string, provider *model.IDPProviderView) error {
|
|
||||||
save := repository.PrepareSave(table)
|
|
||||||
return save(db, provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutIDPProviders(db *gorm.DB, table string, providers ...*model.IDPProviderView) error {
|
|
||||||
save := repository.PrepareBulkSave(table)
|
|
||||||
p := make([]interface{}, len(providers))
|
|
||||||
for i, provider := range providers {
|
|
||||||
p[i] = provider
|
|
||||||
}
|
|
||||||
return save(db, p...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteIDPProvider(db *gorm.DB, table, aggregateID, idpConfigID, instanceID string) error {
|
|
||||||
delete := repository.PrepareDeleteByKeys(table,
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyIdpConfigID), Value: idpConfigID},
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID},
|
|
||||||
)
|
|
||||||
return delete(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteIDPProvidersByAggregateID(db *gorm.DB, table, aggregateID, instanceID string) error {
|
|
||||||
delete := repository.PrepareDeleteByKeys(table,
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggregateID},
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID},
|
|
||||||
)
|
|
||||||
return delete(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteInstanceIDPProviders(db *gorm.DB, table, instanceID string) error {
|
|
||||||
delete := repository.PrepareDeleteByKey(table,
|
|
||||||
model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID),
|
|
||||||
instanceID,
|
|
||||||
)
|
|
||||||
return delete(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateOrgOwnerRemovedIDPProviders(db *gorm.DB, table, instanceID, aggID string) error {
|
|
||||||
update := repository.PrepareUpdateByKeys(table,
|
|
||||||
model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyOwnerRemoved),
|
|
||||||
true,
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyInstanceID), Value: instanceID},
|
|
||||||
repository.Key{Key: model.IDPProviderSearchKey(iam_model.IDPProviderSearchKeyAggregateID), Value: aggID},
|
|
||||||
)
|
|
||||||
return update(db)
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
package view
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/iam/repository/view/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/view/repository"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func IDPByID(db *gorm.DB, table, idpID, instanceID string) (*model.IDPConfigView, error) {
|
|
||||||
idp := new(model.IDPConfigView)
|
|
||||||
idpIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyIdpConfigID, Value: idpID, Method: domain.SearchMethodEquals}
|
|
||||||
instanceIDQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyInstanceID, Value: instanceID, Method: domain.SearchMethodEquals}
|
|
||||||
ownerRemovedQuery := &model.IDPConfigSearchQuery{Key: iam_model.IDPConfigSearchKeyOwnerRemoved, Value: false, Method: domain.SearchMethodEquals}
|
|
||||||
query := repository.PrepareGetByQuery(table, idpIDQuery, instanceIDQuery, ownerRemovedQuery)
|
|
||||||
err := query(db, idp)
|
|
||||||
if zerrors.IsNotFound(err) {
|
|
||||||
return nil, zerrors.ThrowNotFound(nil, "VIEW-Ahq2s", "Errors.IDP.NotExisting")
|
|
||||||
}
|
|
||||||
return idp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIDPConfigsByAggregateID(db *gorm.DB, table string, aggregateID, instanceID string) ([]*model.IDPConfigView, error) {
|
|
||||||
idps := make([]*model.IDPConfigView, 0)
|
|
||||||
queries := []*iam_model.IDPConfigSearchQuery{
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPConfigSearchKeyAggregateID,
|
|
||||||
Value: aggregateID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
}, {
|
|
||||||
Key: iam_model.IDPConfigSearchKeyInstanceID,
|
|
||||||
Value: instanceID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: iam_model.IDPConfigSearchKeyOwnerRemoved,
|
|
||||||
Value: false,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Queries: queries})
|
|
||||||
_, err := query(db, &idps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return idps, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SearchIDPs(db *gorm.DB, table string, req *iam_model.IDPConfigSearchRequest) ([]*model.IDPConfigView, uint64, error) {
|
|
||||||
idps := make([]*model.IDPConfigView, 0)
|
|
||||||
query := repository.PrepareSearchQuery(table, model.IDPConfigSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
|
|
||||||
count, err := query(db, &idps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
return idps, count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func PutIDP(db *gorm.DB, table string, idp *model.IDPConfigView) error {
|
|
||||||
save := repository.PrepareSave(table)
|
|
||||||
return save(db, idp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteIDP(db *gorm.DB, table, idpID, instanceID string) error {
|
|
||||||
delete := repository.PrepareDeleteByKeys(table,
|
|
||||||
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyIdpConfigID), idpID},
|
|
||||||
repository.Key{model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID},
|
|
||||||
)
|
|
||||||
return delete(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateOrgOwnerRemovedIDPs(db *gorm.DB, table, instanceID, aggID string) error {
|
|
||||||
update := repository.PrepareUpdateByKeys(table,
|
|
||||||
model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyOwnerRemoved),
|
|
||||||
true,
|
|
||||||
repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), Value: instanceID},
|
|
||||||
repository.Key{Key: model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyAggregateID), Value: aggID},
|
|
||||||
)
|
|
||||||
return update(db)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeleteInstanceIDPs(db *gorm.DB, table, instanceID string) error {
|
|
||||||
delete := repository.PrepareDeleteByKey(table, model.IDPConfigSearchKey(iam_model.IDPConfigSearchKeyInstanceID), instanceID)
|
|
||||||
return delete(db)
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
|
||||||
"github.com/zitadel/zitadel/internal/database"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
|
||||||
"github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/org"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPConfigKeyIdpConfigID = "idp_config_id"
|
|
||||||
IDPConfigKeyAggregateID = "aggregate_id"
|
|
||||||
IDPConfigKeyName = "name"
|
|
||||||
IDPConfigKeyProviderType = "idp_provider_type"
|
|
||||||
IDPConfigKeyInstanceID = "instance_id"
|
|
||||||
IDPConfigKeyOwnerRemoved = "owner_removed"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfigView struct {
|
|
||||||
IDPConfigID string `json:"idpConfigId" gorm:"column:idp_config_id;primary_key"`
|
|
||||||
AggregateID string `json:"-" gorm:"column:aggregate_id"`
|
|
||||||
Name string `json:"name" gorm:"column:name"`
|
|
||||||
StylingType int32 `json:"stylingType" gorm:"column:styling_type"`
|
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
|
||||||
IDPState int32 `json:"-" gorm:"column:idp_state"`
|
|
||||||
IDPProviderType int32 `json:"-" gorm:"column:idp_provider_type"`
|
|
||||||
AutoRegister bool `json:"autoRegister" gorm:"column:auto_register"`
|
|
||||||
|
|
||||||
IsOIDC bool `json:"-" gorm:"column:is_oidc"`
|
|
||||||
OIDCClientID string `json:"clientId" gorm:"column:oidc_client_id"`
|
|
||||||
OIDCClientSecret *crypto.CryptoValue `json:"clientSecret" gorm:"column:oidc_client_secret"`
|
|
||||||
OIDCIssuer string `json:"issuer" gorm:"column:oidc_issuer"`
|
|
||||||
OIDCScopes database.TextArray[string] `json:"scopes" gorm:"column:oidc_scopes"`
|
|
||||||
OIDCIDPDisplayNameMapping int32 `json:"idpDisplayNameMapping" gorm:"column:oidc_idp_display_name_mapping"`
|
|
||||||
OIDCUsernameMapping int32 `json:"usernameMapping" gorm:"column:oidc_idp_username_mapping"`
|
|
||||||
OAuthAuthorizationEndpoint string `json:"authorizationEndpoint" gorm:"column:oauth_authorization_endpoint"`
|
|
||||||
OAuthTokenEndpoint string `json:"tokenEndpoint" gorm:"column:oauth_token_endpoint"`
|
|
||||||
JWTEndpoint string `json:"jwtEndpoint" gorm:"jwt_endpoint"`
|
|
||||||
JWTKeysEndpoint string `json:"keysEndpoint" gorm:"jwt_keys_endpoint"`
|
|
||||||
JWTHeaderName string `json:"headerName" gorm:"jwt_header_name"`
|
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
|
||||||
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPConfigViewToModel(idp *IDPConfigView) *model.IDPConfigView {
|
|
||||||
view := &model.IDPConfigView{
|
|
||||||
IDPConfigID: idp.IDPConfigID,
|
|
||||||
AggregateID: idp.AggregateID,
|
|
||||||
State: model.IDPConfigState(idp.IDPState),
|
|
||||||
Name: idp.Name,
|
|
||||||
StylingType: model.IDPStylingType(idp.StylingType),
|
|
||||||
AutoRegister: idp.AutoRegister,
|
|
||||||
Sequence: idp.Sequence,
|
|
||||||
CreationDate: idp.CreationDate,
|
|
||||||
ChangeDate: idp.ChangeDate,
|
|
||||||
IDPProviderType: model.IDPProviderType(idp.IDPProviderType),
|
|
||||||
IsOIDC: idp.IsOIDC,
|
|
||||||
OIDCClientID: idp.OIDCClientID,
|
|
||||||
OIDCClientSecret: idp.OIDCClientSecret,
|
|
||||||
OIDCScopes: idp.OIDCScopes,
|
|
||||||
OIDCIDPDisplayNameMapping: model.OIDCMappingField(idp.OIDCIDPDisplayNameMapping),
|
|
||||||
OIDCUsernameMapping: model.OIDCMappingField(idp.OIDCUsernameMapping),
|
|
||||||
OAuthAuthorizationEndpoint: idp.OAuthAuthorizationEndpoint,
|
|
||||||
OAuthTokenEndpoint: idp.OAuthTokenEndpoint,
|
|
||||||
}
|
|
||||||
if idp.IsOIDC {
|
|
||||||
view.OIDCIssuer = idp.OIDCIssuer
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
view.JWTEndpoint = idp.JWTEndpoint
|
|
||||||
view.JWTIssuer = idp.OIDCIssuer
|
|
||||||
view.JWTKeysEndpoint = idp.JWTKeysEndpoint
|
|
||||||
view.JWTHeaderName = idp.JWTHeaderName
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IDPConfigView) AppendEvent(providerType model.IDPProviderType, event eventstore.Event) (err error) {
|
|
||||||
i.Sequence = event.Sequence()
|
|
||||||
i.ChangeDate = event.CreatedAt()
|
|
||||||
switch event.Type() {
|
|
||||||
case instance.IDPConfigAddedEventType, org.IDPConfigAddedEventType:
|
|
||||||
i.setRootData(event)
|
|
||||||
i.CreationDate = event.CreatedAt()
|
|
||||||
i.IDPProviderType = int32(providerType)
|
|
||||||
err = i.SetData(event)
|
|
||||||
case instance.IDPOIDCConfigAddedEventType, org.IDPOIDCConfigAddedEventType:
|
|
||||||
i.IsOIDC = true
|
|
||||||
err = i.SetData(event)
|
|
||||||
case instance.IDPOIDCConfigChangedEventType, org.IDPOIDCConfigChangedEventType,
|
|
||||||
instance.IDPConfigChangedEventType, org.IDPConfigChangedEventType,
|
|
||||||
org.IDPJWTConfigAddedEventType, instance.IDPJWTConfigAddedEventType,
|
|
||||||
org.IDPJWTConfigChangedEventType, instance.IDPJWTConfigChangedEventType:
|
|
||||||
err = i.SetData(event)
|
|
||||||
case instance.IDPConfigDeactivatedEventType, org.IDPConfigDeactivatedEventType:
|
|
||||||
i.IDPState = int32(model.IDPConfigStateInactive)
|
|
||||||
case instance.IDPConfigReactivatedEventType, org.IDPConfigReactivatedEventType:
|
|
||||||
i.IDPState = int32(model.IDPConfigStateActive)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPConfigView) setRootData(event eventstore.Event) {
|
|
||||||
r.AggregateID = event.Aggregate().ID
|
|
||||||
r.InstanceID = event.Aggregate().InstanceID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPConfigView) SetData(event eventstore.Event) error {
|
|
||||||
err := event.Unmarshal(r)
|
|
||||||
if err != nil {
|
|
||||||
logging.New().WithError(err).Error("could not unmarshal event data")
|
|
||||||
return zerrors.ThrowInternal(err, "MODEL-lub6s", "Could not unmarshal data")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/view/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPConfigSearchRequest iam_model.IDPConfigSearchRequest
|
|
||||||
type IDPConfigSearchQuery iam_model.IDPConfigSearchQuery
|
|
||||||
type IDPConfigSearchKey iam_model.IDPConfigSearchKey
|
|
||||||
|
|
||||||
func (req IDPConfigSearchRequest) GetLimit() uint64 {
|
|
||||||
return req.Limit
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchRequest) GetOffset() uint64 {
|
|
||||||
return req.Offset
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchRequest) GetSortingColumn() repository.ColumnKey {
|
|
||||||
if req.SortingColumn == iam_model.IDPConfigSearchKeyUnspecified {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return IDPConfigSearchKey(req.SortingColumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchRequest) GetAsc() bool {
|
|
||||||
return req.Asc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchRequest) GetQueries() []repository.SearchQuery {
|
|
||||||
result := make([]repository.SearchQuery, len(req.Queries))
|
|
||||||
for i, q := range req.Queries {
|
|
||||||
result[i] = IDPConfigSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchQuery) GetKey() repository.ColumnKey {
|
|
||||||
return IDPConfigSearchKey(req.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchQuery) GetMethod() domain.SearchMethod {
|
|
||||||
return req.Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPConfigSearchQuery) GetValue() interface{} {
|
|
||||||
return req.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (key IDPConfigSearchKey) ToColumnName() string {
|
|
||||||
switch iam_model.IDPConfigSearchKey(key) {
|
|
||||||
case iam_model.IDPConfigSearchKeyAggregateID:
|
|
||||||
return IDPConfigKeyAggregateID
|
|
||||||
case iam_model.IDPConfigSearchKeyIdpConfigID:
|
|
||||||
return IDPConfigKeyIdpConfigID
|
|
||||||
case iam_model.IDPConfigSearchKeyName:
|
|
||||||
return IDPConfigKeyName
|
|
||||||
case iam_model.IDPConfigSearchKeyIdpProviderType:
|
|
||||||
return IDPConfigKeyProviderType
|
|
||||||
case iam_model.IDPConfigSearchKeyInstanceID:
|
|
||||||
return IDPConfigKeyInstanceID
|
|
||||||
case iam_model.IDPConfigSearchKeyOwnerRemoved:
|
|
||||||
return IDPConfigKeyOwnerRemoved
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
|
||||||
"github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/org"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
IDPProviderKeyAggregateID = "aggregate_id"
|
|
||||||
IDPProviderKeyIdpConfigID = "idp_config_id"
|
|
||||||
IDPProviderKeyState = "idp_state"
|
|
||||||
IDPProviderKeyInstanceID = "instance_id"
|
|
||||||
IDPProviderKeyOwnerRemoved = "owner_removed"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPProviderView struct {
|
|
||||||
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
|
|
||||||
IDPConfigID string `json:"idpConfigID" gorm:"column:idp_config_id;primary_key"`
|
|
||||||
|
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
|
||||||
|
|
||||||
Name string `json:"-" gorm:"column:name"`
|
|
||||||
StylingType int32 `json:"-" gorm:"column:styling_type"`
|
|
||||||
IDPConfigType int32 `json:"-" gorm:"column:idp_config_type"`
|
|
||||||
IDPProviderType int32 `json:"idpProviderType" gorm:"column:idp_provider_type"`
|
|
||||||
IDPState int32 `json:"-" gorm:"column:idp_state"`
|
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
|
||||||
InstanceID string `json:"instanceID" gorm:"column:instance_id;primary_key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPProviderViewToModel(provider *IDPProviderView) *model.IDPProviderView {
|
|
||||||
return &model.IDPProviderView{
|
|
||||||
AggregateID: provider.AggregateID,
|
|
||||||
Sequence: provider.Sequence,
|
|
||||||
CreationDate: provider.CreationDate,
|
|
||||||
ChangeDate: provider.ChangeDate,
|
|
||||||
Name: provider.Name,
|
|
||||||
StylingType: model.IDPStylingType(provider.StylingType),
|
|
||||||
IDPConfigID: provider.IDPConfigID,
|
|
||||||
IDPConfigType: model.IdpConfigType(provider.IDPConfigType),
|
|
||||||
IDPProviderType: model.IDPProviderType(provider.IDPProviderType),
|
|
||||||
IDPState: model.IDPConfigState(provider.IDPState),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func IDPProviderViewsToModel(providers []*IDPProviderView) []*model.IDPProviderView {
|
|
||||||
result := make([]*model.IDPProviderView, len(providers))
|
|
||||||
for i, r := range providers {
|
|
||||||
result[i] = IDPProviderViewToModel(r)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *IDPProviderView) AppendEvent(event eventstore.Event) (err error) {
|
|
||||||
i.Sequence = event.Sequence()
|
|
||||||
i.ChangeDate = event.CreatedAt()
|
|
||||||
switch event.Type() {
|
|
||||||
case instance.LoginPolicyIDPProviderAddedEventType,
|
|
||||||
org.LoginPolicyIDPProviderAddedEventType:
|
|
||||||
i.setRootData(event)
|
|
||||||
i.CreationDate = event.CreatedAt()
|
|
||||||
err = i.SetData(event)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPProviderView) setRootData(event eventstore.Event) {
|
|
||||||
r.AggregateID = event.Aggregate().ID
|
|
||||||
r.InstanceID = event.Aggregate().InstanceID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IDPProviderView) SetData(event eventstore.Event) error {
|
|
||||||
if err := event.Unmarshal(r); err != nil {
|
|
||||||
logging.New().WithError(err).Error("could not unmarshal event data")
|
|
||||||
return zerrors.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
|
||||||
"github.com/zitadel/zitadel/internal/view/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
type IDPProviderSearchRequest iam_model.IDPProviderSearchRequest
|
|
||||||
type IDPProviderSearchQuery iam_model.IDPProviderSearchQuery
|
|
||||||
type IDPProviderSearchKey iam_model.IDPProviderSearchKey
|
|
||||||
|
|
||||||
func (req IDPProviderSearchRequest) GetLimit() uint64 {
|
|
||||||
return req.Limit
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchRequest) GetOffset() uint64 {
|
|
||||||
return req.Offset
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchRequest) GetSortingColumn() repository.ColumnKey {
|
|
||||||
if req.SortingColumn == iam_model.IDPProviderSearchKeyUnspecified {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return IDPProviderSearchKey(req.SortingColumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchRequest) GetAsc() bool {
|
|
||||||
return req.Asc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchRequest) GetQueries() []repository.SearchQuery {
|
|
||||||
result := make([]repository.SearchQuery, len(req.Queries))
|
|
||||||
for i, q := range req.Queries {
|
|
||||||
result[i] = IDPProviderSearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchQuery) GetKey() repository.ColumnKey {
|
|
||||||
return IDPProviderSearchKey(req.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchQuery) GetMethod() domain.SearchMethod {
|
|
||||||
return req.Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req IDPProviderSearchQuery) GetValue() interface{} {
|
|
||||||
return req.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (key IDPProviderSearchKey) ToColumnName() string {
|
|
||||||
switch iam_model.IDPProviderSearchKey(key) {
|
|
||||||
case iam_model.IDPProviderSearchKeyAggregateID:
|
|
||||||
return IDPProviderKeyAggregateID
|
|
||||||
case iam_model.IDPProviderSearchKeyIdpConfigID:
|
|
||||||
return IDPProviderKeyIdpConfigID
|
|
||||||
case iam_model.IDPProviderSearchKeyState:
|
|
||||||
return IDPProviderKeyState
|
|
||||||
case iam_model.IDPProviderSearchKeyInstanceID:
|
|
||||||
return IDPProviderKeyInstanceID
|
|
||||||
case iam_model.IDPProviderSearchKeyOwnerRemoved:
|
|
||||||
return IDPProviderKeyOwnerRemoved
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,37 +6,9 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/view/repository"
|
"github.com/zitadel/zitadel/internal/view/repository"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LabelPolicySearchRequest iam_model.LabelPolicySearchRequest
|
|
||||||
type LabelPolicySearchQuery iam_model.LabelPolicySearchQuery
|
type LabelPolicySearchQuery iam_model.LabelPolicySearchQuery
|
||||||
type LabelPolicySearchKey iam_model.LabelPolicySearchKey
|
type LabelPolicySearchKey iam_model.LabelPolicySearchKey
|
||||||
|
|
||||||
func (req LabelPolicySearchRequest) GetLimit() uint64 {
|
|
||||||
return req.Limit
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req LabelPolicySearchRequest) GetOffset() uint64 {
|
|
||||||
return req.Offset
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req LabelPolicySearchRequest) GetSortingColumn() repository.ColumnKey {
|
|
||||||
if req.SortingColumn == iam_model.LabelPolicySearchKeyUnspecified {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return LabelPolicySearchKey(req.SortingColumn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req LabelPolicySearchRequest) GetAsc() bool {
|
|
||||||
return req.Asc
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req LabelPolicySearchRequest) GetQueries() []repository.SearchQuery {
|
|
||||||
result := make([]repository.SearchQuery, len(req.Queries))
|
|
||||||
for i, q := range req.Queries {
|
|
||||||
result[i] = LabelPolicySearchQuery{Key: q.Key, Value: q.Value, Method: q.Method}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req LabelPolicySearchQuery) GetKey() repository.ColumnKey {
|
func (req LabelPolicySearchQuery) GetKey() repository.ColumnKey {
|
||||||
return LabelPolicySearchKey(req.Key)
|
return LabelPolicySearchKey(req.Key)
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,10 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
|
||||||
"github.com/zitadel/zitadel/internal/iam/model"
|
"github.com/zitadel/zitadel/internal/iam/model"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
|
||||||
"github.com/zitadel/zitadel/internal/repository/org"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
PasswordComplexityKeyAggregateID = "aggregate_id"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PasswordComplexityPolicyView struct {
|
|
||||||
AggregateID string `json:"-" gorm:"column:aggregate_id;primary_key"`
|
|
||||||
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
|
|
||||||
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
|
|
||||||
State int32 `json:"-" gorm:"column:complexity_policy_state"`
|
|
||||||
|
|
||||||
MinLength uint64 `json:"minLength" gorm:"column:min_length"`
|
|
||||||
HasLowercase bool `json:"hasLowercase" gorm:"column:has_lowercase"`
|
|
||||||
HasUppercase bool `json:"hasUppercase" gorm:"column:has_uppercase"`
|
|
||||||
HasSymbol bool `json:"hasSymbol" gorm:"column:has_symbol"`
|
|
||||||
HasNumber bool `json:"hasNumber" gorm:"column:has_number"`
|
|
||||||
Default bool `json:"-" gorm:"-"`
|
|
||||||
|
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func PasswordComplexityViewToModel(policy *query.PasswordComplexityPolicy) *model.PasswordComplexityPolicyView {
|
func PasswordComplexityViewToModel(policy *query.PasswordComplexityPolicy) *model.PasswordComplexityPolicyView {
|
||||||
return &model.PasswordComplexityPolicyView{
|
return &model.PasswordComplexityPolicyView{
|
||||||
AggregateID: policy.ID,
|
AggregateID: policy.ID,
|
||||||
@ -47,31 +19,3 @@ func PasswordComplexityViewToModel(policy *query.PasswordComplexityPolicy) *mode
|
|||||||
Default: policy.IsDefault,
|
Default: policy.IsDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *PasswordComplexityPolicyView) AppendEvent(event eventstore.Event) (err error) {
|
|
||||||
i.Sequence = event.Sequence()
|
|
||||||
i.ChangeDate = event.CreatedAt()
|
|
||||||
switch event.Type() {
|
|
||||||
case instance.PasswordComplexityPolicyAddedEventType,
|
|
||||||
org.PasswordComplexityPolicyAddedEventType:
|
|
||||||
i.setRootData(event)
|
|
||||||
i.CreationDate = event.CreatedAt()
|
|
||||||
err = i.SetData(event)
|
|
||||||
case instance.PasswordComplexityPolicyChangedEventType,
|
|
||||||
org.PasswordComplexityPolicyChangedEventType:
|
|
||||||
err = i.SetData(event)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *PasswordComplexityPolicyView) setRootData(event eventstore.Event) {
|
|
||||||
r.AggregateID = event.Aggregate().ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *PasswordComplexityPolicyView) SetData(event eventstore.Event) error {
|
|
||||||
if err := event.Unmarshal(r); err != nil {
|
|
||||||
logging.Log("EVEN-Dmi9g").WithError(err).Error("could not unmarshal event data")
|
|
||||||
return zerrors.ThrowInternal(err, "MODEL-Hs8uf", "Could not unmarshal data")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/pkg/grpc/user"
|
"github.com/zitadel/zitadel/pkg/grpc/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, appType app.OIDCAppType, authMethod app.OIDCAuthMethodType) (*management.AddOIDCAppResponse, error) {
|
func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, appType app.OIDCAppType, authMethod app.OIDCAuthMethodType, devMode bool) (*management.AddOIDCAppResponse, error) {
|
||||||
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
|
return s.Client.Mgmt.AddOIDCApp(ctx, &management.AddOIDCAppRequest{
|
||||||
ProjectId: projectID,
|
ProjectId: projectID,
|
||||||
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
|
Name: fmt.Sprintf("app-%d", time.Now().UnixNano()),
|
||||||
@ -34,7 +34,7 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire
|
|||||||
AuthMethodType: authMethod,
|
AuthMethodType: authMethod,
|
||||||
PostLogoutRedirectUris: []string{logoutRedirectURI},
|
PostLogoutRedirectUris: []string{logoutRedirectURI},
|
||||||
Version: app.OIDCVersion_OIDC_VERSION_1_0,
|
Version: app.OIDCVersion_OIDC_VERSION_1_0,
|
||||||
DevMode: false,
|
DevMode: devMode,
|
||||||
AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT,
|
AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT,
|
||||||
AccessTokenRoleAssertion: false,
|
AccessTokenRoleAssertion: false,
|
||||||
IdTokenRoleAssertion: false,
|
IdTokenRoleAssertion: false,
|
||||||
@ -45,16 +45,16 @@ func (s *Tester) CreateOIDCClient(ctx context.Context, redirectURI, logoutRedire
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) {
|
func (s *Tester) CreateOIDCNativeClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string, devMode bool) (*management.AddOIDCAppResponse, error) {
|
||||||
return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE)
|
return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, devMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCWebClientBasic(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) {
|
func (s *Tester) CreateOIDCWebClientBasic(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) {
|
||||||
return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_BASIC)
|
return s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_BASIC, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCWebClientJWT(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (client *management.AddOIDCAppResponse, keyData []byte, err error) {
|
func (s *Tester) CreateOIDCWebClientJWT(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (client *management.AddOIDCAppResponse, keyData []byte, err error) {
|
||||||
client, err = s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT)
|
client, err = s.CreateOIDCClient(ctx, redirectURI, logoutRedirectURI, projectID, app.OIDCAppType_OIDC_APP_TYPE_WEB, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_PRIVATE_KEY_JWT, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ func (s *Tester) CreateOIDCWebClientJWT(ctx context.Context, redirectURI, logout
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCInactivateClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) {
|
func (s *Tester) CreateOIDCInactivateClient(ctx context.Context, redirectURI, logoutRedirectURI, projectID string) (*management.AddOIDCAppResponse, error) {
|
||||||
client, err := s.CreateOIDCNativeClient(ctx, redirectURI, logoutRedirectURI, projectID)
|
client, err := s.CreateOIDCNativeClient(ctx, redirectURI, logoutRedirectURI, projectID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ func (s *Tester) CreateProject(ctx context.Context) (*management.AddProjectRespo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateAPIClient(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) {
|
func (s *Tester) CreateAPIClientJWT(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) {
|
||||||
return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{
|
return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{
|
||||||
ProjectId: projectID,
|
ProjectId: projectID,
|
||||||
Name: fmt.Sprintf("api-%d", time.Now().UnixNano()),
|
Name: fmt.Sprintf("api-%d", time.Now().UnixNano()),
|
||||||
@ -127,6 +127,14 @@ func (s *Tester) CreateAPIClient(ctx context.Context, projectID string) (*manage
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Tester) CreateAPIClientBasic(ctx context.Context, projectID string) (*management.AddAPIAppResponse, error) {
|
||||||
|
return s.Client.Mgmt.AddAPIApp(ctx, &management.AddAPIAppRequest{
|
||||||
|
ProjectId: projectID,
|
||||||
|
Name: fmt.Sprintf("api-%d", time.Now().UnixNano()),
|
||||||
|
AuthMethodType: app.APIAuthMethodType_API_AUTH_METHOD_TYPE_BASIC,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const CodeVerifier = "codeVerifier"
|
const CodeVerifier = "codeVerifier"
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCAuthRequest(ctx context.Context, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
func (s *Tester) CreateOIDCAuthRequest(ctx context.Context, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
||||||
@ -207,7 +215,7 @@ func (c *loginRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
|
|||||||
return c.RoundTripper.RoundTrip(req)
|
return c.RoundTripper.RoundTrip(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateResourceServer(ctx context.Context, keyFileData []byte) (rs.ResourceServer, error) {
|
func (s *Tester) CreateResourceServerJWTProfile(ctx context.Context, keyFileData []byte) (rs.ResourceServer, error) {
|
||||||
keyFile, err := client.ConfigFromKeyFileData(keyFileData)
|
keyFile, err := client.ConfigFromKeyFileData(keyFileData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -215,6 +223,10 @@ func (s *Tester) CreateResourceServer(ctx context.Context, keyFileData []byte) (
|
|||||||
return rs.NewResourceServerJWTProfile(ctx, s.OIDCIssuer(), keyFile.ClientID, keyFile.KeyID, []byte(keyFile.Key))
|
return rs.NewResourceServerJWTProfile(ctx, s.OIDCIssuer(), keyFile.ClientID, keyFile.KeyID, []byte(keyFile.Key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Tester) CreateResourceServerClientCredentials(ctx context.Context, clientID, clientSecret string) (rs.ResourceServer, error) {
|
||||||
|
return rs.NewResourceServerClientCredentials(ctx, s.OIDCIssuer(), clientID, clientSecret)
|
||||||
|
}
|
||||||
|
|
||||||
func GetRequest(url string, headers map[string]string) (*http.Request, error) {
|
func GetRequest(url string, headers map[string]string) (*http.Request, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
)
|
)
|
||||||
@ -22,35 +21,3 @@ const (
|
|||||||
OrgDomainValidationTypeHTTP
|
OrgDomainValidationTypeHTTP
|
||||||
OrgDomainValidationTypeDNS
|
OrgDomainValidationTypeDNS
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t OrgDomainValidationType) CheckType() (http_util.CheckType, bool) {
|
|
||||||
switch t {
|
|
||||||
case OrgDomainValidationTypeHTTP:
|
|
||||||
return http_util.CheckTypeHTTP, true
|
|
||||||
case OrgDomainValidationTypeDNS:
|
|
||||||
return http_util.CheckTypeDNS, true
|
|
||||||
default:
|
|
||||||
return -1, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t OrgDomainValidationType) IsDNS() bool {
|
|
||||||
return t == OrgDomainValidationTypeDNS
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOrgDomain(orgID, domain string) *OrgDomain {
|
|
||||||
return &OrgDomain{ObjectRoot: es_models.ObjectRoot{AggregateID: orgID}, Domain: domain}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (domain *OrgDomain) IsValid() bool {
|
|
||||||
return domain.AggregateID != "" && domain.Domain != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (domain *OrgDomain) GenerateVerificationCode(codeGenerator crypto.Generator) (string, error) {
|
|
||||||
validationCodeCrypto, validationCode, err := crypto.NewCode(codeGenerator)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
domain.ValidationCode = validationCodeCrypto
|
|
||||||
return validationCode, nil
|
|
||||||
}
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OrgMember struct {
|
|
||||||
es_models.ObjectRoot `json:"-"`
|
|
||||||
|
|
||||||
UserID string `json:"userId,omitempty"`
|
|
||||||
Roles []string `json:"roles,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *OrgMember) AppendEvents(events ...*es_models.Event) error {
|
|
||||||
for _, event := range events {
|
|
||||||
err := m.AppendEvent(event)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *OrgMember) AppendEvent(event *es_models.Event) error {
|
|
||||||
m.ObjectRoot.AppendEvent(event)
|
|
||||||
|
|
||||||
return m.SetData(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *OrgMember) SetData(event *es_models.Event) error {
|
|
||||||
err := json.Unmarshal(event.Data, m)
|
|
||||||
if err != nil {
|
|
||||||
return zerrors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *OrgMember) Changes(updatedMember *OrgMember) map[string]interface{} {
|
|
||||||
changes := make(map[string]interface{}, 2)
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(m.Roles, updatedMember.Roles) {
|
|
||||||
changes["roles"] = updatedMember.Roles
|
|
||||||
changes["userId"] = m.UserID
|
|
||||||
}
|
|
||||||
|
|
||||||
return changes
|
|
||||||
}
|
|
@ -97,13 +97,3 @@ func (o *Org) SetData(event eventstore.Event) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Org) Changes(changed *Org) map[string]interface{} {
|
|
||||||
changes := make(map[string]interface{}, 2)
|
|
||||||
|
|
||||||
if changed.Name != "" && changed.Name != o.Name {
|
|
||||||
changes["name"] = changed.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
return changes
|
|
||||||
}
|
|
||||||
|
@ -116,47 +116,3 @@ func TestAppendEvent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChanges(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
existingOrg *Org
|
|
||||||
newOrg *Org
|
|
||||||
}
|
|
||||||
type res struct {
|
|
||||||
changesLen int
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
res res
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "org name changes",
|
|
||||||
args: args{
|
|
||||||
existingOrg: &Org{Name: "Name"},
|
|
||||||
newOrg: &Org{Name: "NameChanged"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no changes",
|
|
||||||
args: args{
|
|
||||||
existingOrg: &Org{Name: "Name"},
|
|
||||||
newOrg: &Org{Name: "Name"},
|
|
||||||
},
|
|
||||||
res: res{
|
|
||||||
changesLen: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
changes := tt.args.existingOrg.Changes(tt.args.newOrg)
|
|
||||||
if len(changes) != tt.res.changesLen {
|
|
||||||
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/id"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIConfig struct {
|
type APIConfig struct {
|
||||||
@ -27,35 +20,3 @@ const (
|
|||||||
APIAuthMethodTypeBasic APIAuthMethodType = iota
|
APIAuthMethodTypeBasic APIAuthMethodType = iota
|
||||||
APIAuthMethodTypePrivateKeyJWT
|
APIAuthMethodTypePrivateKeyJWT
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *APIConfig) IsValid() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientID random_number@projectname (eg. 495894098234@zitadel)
|
|
||||||
func (c *APIConfig) GenerateNewClientID(idGenerator id.Generator, project *Project) error {
|
|
||||||
rndID, err := idGenerator.Next()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *APIConfig) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) {
|
|
||||||
if c.AuthMethodType == APIAuthMethodTypeBasic {
|
|
||||||
return c.GenerateNewClientSecret(generator)
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *APIConfig) GenerateNewClientSecret(generator crypto.Generator) (string, error) {
|
|
||||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("MODEL-ADvd2").OnError(err).Error("unable to create client secret")
|
|
||||||
return "", zerrors.ThrowInternal(err, "MODEL-dsvr43", "Errors.Project.CouldNotGenerateClientSecret")
|
|
||||||
}
|
|
||||||
c.ClientSecret = cryptoValue
|
|
||||||
return stringSecret, nil
|
|
||||||
}
|
|
||||||
|
@ -32,22 +32,3 @@ const (
|
|||||||
AppTypeSAML
|
AppTypeSAML
|
||||||
AppTypeAPI
|
AppTypeAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *Application) IsValid(includeConfig bool) bool {
|
|
||||||
if a.Name == "" || a.AggregateID == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !includeConfig {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if a.Type == AppTypeOIDC && !a.OIDCConfig.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if a.Type == AppTypeAPI && !a.APIConfig.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if a.Type == AppTypeSAML && !a.SAMLConfig.IsValid() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
@ -1,171 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestApplicationValid(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
app *Application
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
result bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype code",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid oidc application: responsetype code",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid oidc application: responsetype id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype token_id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDTokenToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "invalid oidc application: responsetype token_id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeIDTokenToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype code & id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype code & token_id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDTokenToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid oidc application: responsetype code & id_token & token_id_token",
|
|
||||||
args: args{
|
|
||||||
app: &Application{
|
|
||||||
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
|
|
||||||
AppID: "AppID",
|
|
||||||
Name: "Name",
|
|
||||||
Type: AppTypeOIDC,
|
|
||||||
OIDCConfig: &OIDCConfig{
|
|
||||||
ResponseTypes: []OIDCResponseType{OIDCResponseTypeCode, OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken},
|
|
||||||
GrantTypes: []OIDCGrantType{OIDCGrantTypeAuthorizationCode, OIDCGrantTypeImplicit},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
result: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result := tt.args.app.IsValid(true)
|
|
||||||
if result != tt.result {
|
|
||||||
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,11 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/zitadel/logging"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||||
"github.com/zitadel/zitadel/internal/id"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OIDCConfig struct {
|
type OIDCConfig struct {
|
||||||
@ -97,49 +91,6 @@ type Token struct {
|
|||||||
Scopes []string
|
Scopes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OIDCConfig) IsValid() bool {
|
|
||||||
grantTypes := c.getRequiredGrantTypes()
|
|
||||||
for _, grantType := range grantTypes {
|
|
||||||
ok := containsOIDCGrantType(c.GrantTypes, grantType)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientID random_number@projectname (eg. 495894098234@zitadel)
|
|
||||||
func (c *OIDCConfig) GenerateNewClientID(idGenerator id.Generator, project *Project) error {
|
|
||||||
rndID, err := idGenerator.Next()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *OIDCConfig) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) {
|
|
||||||
if c.AuthMethodType == OIDCAuthMethodTypeBasic || c.AuthMethodType == OIDCAuthMethodTypePost {
|
|
||||||
return c.GenerateNewClientSecret(generator)
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *OIDCConfig) GenerateNewClientSecret(generator crypto.Generator) (string, error) {
|
|
||||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
|
||||||
if err != nil {
|
|
||||||
logging.Log("MODEL-UpnTI").OnError(err).Error("unable to create client secret")
|
|
||||||
return "", zerrors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret")
|
|
||||||
}
|
|
||||||
c.ClientSecret = cryptoValue
|
|
||||||
return stringSecret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *OIDCConfig) FillCompliance() {
|
|
||||||
c.Compliance = GetOIDCCompliance(c.OIDCVersion, c.ApplicationType, c.GrantTypes, c.ResponseTypes, c.AuthMethodType, c.RedirectUris)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTypes []OIDCGrantType, responseTypes []OIDCResponseType, authMethod OIDCAuthMethodType, redirectUris []string) *Compliance {
|
func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTypes []OIDCGrantType, responseTypes []OIDCResponseType, authMethod OIDCAuthMethodType, redirectUris []string) *Compliance {
|
||||||
switch version {
|
switch version {
|
||||||
case OIDCVersionV1:
|
case OIDCVersionV1:
|
||||||
@ -155,29 +106,3 @@ func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTy
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *OIDCConfig) getRequiredGrantTypes() []OIDCGrantType {
|
|
||||||
grantTypes := make([]OIDCGrantType, 0)
|
|
||||||
implicit := false
|
|
||||||
for _, r := range c.ResponseTypes {
|
|
||||||
switch r {
|
|
||||||
case OIDCResponseTypeCode:
|
|
||||||
grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode)
|
|
||||||
case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken:
|
|
||||||
if !implicit {
|
|
||||||
implicit = true
|
|
||||||
grantTypes = append(grantTypes, OIDCGrantTypeImplicit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return grantTypes
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsOIDCGrantType(grantTypes []OIDCGrantType, grantType OIDCGrantType) bool {
|
|
||||||
for _, gt := range grantTypes {
|
|
||||||
if gt == grantType {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OrgProjectMapping struct {
|
|
||||||
OrgID string
|
|
||||||
ProjectID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type OrgProjectMappingViewSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn OrgProjectMappingViewSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*OrgProjectMappingViewSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type OrgProjectMappingViewSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
OrgProjectMappingSearchKeyUnspecified OrgProjectMappingViewSearchKey = iota
|
|
||||||
OrgProjectMappingSearchKeyProjectID
|
|
||||||
OrgProjectMappingSearchKeyOrgID
|
|
||||||
OrgProjectMappingSearchKeyProjectGrantID
|
|
||||||
OrgProjectMappingSearchKeyInstanceID
|
|
||||||
OrgProjectMappingSearchKeyOwnerRemoved
|
|
||||||
)
|
|
||||||
|
|
||||||
type OrgProjectMappingViewSearchQuery struct {
|
|
||||||
Key OrgProjectMappingViewSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type OrgProjectMappingViewSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*OrgProjectMapping
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *OrgProjectMappingViewSearchRequest) GetSearchQuery(key OrgProjectMappingViewSearchKey) (int, *OrgProjectMappingViewSearchQuery) {
|
|
||||||
for i, q := range r.Queries {
|
|
||||||
if q.Key == key {
|
|
||||||
return i, q
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
@ -27,68 +27,3 @@ const (
|
|||||||
ProjectStateInactive
|
ProjectStateInactive
|
||||||
ProjectStateRemoved
|
ProjectStateRemoved
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Project) IsActive() bool {
|
|
||||||
return p.State == ProjectStateActive
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) IsValid() bool {
|
|
||||||
return p.Name != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) ContainsRole(role *ProjectRole) bool {
|
|
||||||
for _, r := range p.Roles {
|
|
||||||
if r.Key == role.Key {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) GetApp(appID string) (int, *Application) {
|
|
||||||
for i, a := range p.Applications {
|
|
||||||
if a.AppID == appID {
|
|
||||||
return i, a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) GetGrant(grantID string) (int, *ProjectGrant) {
|
|
||||||
for i, g := range p.Grants {
|
|
||||||
if g.GrantID == grantID {
|
|
||||||
return i, g
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) ContainsGrantForOrg(orgID string) bool {
|
|
||||||
for _, g := range p.Grants {
|
|
||||||
if g.GrantedOrgID == orgID {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) ContainsRoles(roleKeys []string) bool {
|
|
||||||
for _, r := range roleKeys {
|
|
||||||
if !p.ContainsRole(&ProjectRole{Key: r}) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) ContainsGrantMember(member *ProjectGrantMember) bool {
|
|
||||||
for _, g := range p.Grants {
|
|
||||||
if g.GrantID != member.GrantID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, m := g.GetMember(member.UserID); m != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -14,54 +14,9 @@ type ProjectGrant struct {
|
|||||||
Members []*ProjectGrantMember
|
Members []*ProjectGrantMember
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectGrantIDs struct {
|
|
||||||
ProjectID string
|
|
||||||
GrantID string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantState int32
|
type ProjectGrantState int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProjectGrantStateActive ProjectGrantState = iota
|
ProjectGrantStateActive ProjectGrantState = iota
|
||||||
ProjectGrantStateInactive
|
ProjectGrantStateInactive
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewProjectGrant(projectID, grantID string) *ProjectGrant {
|
|
||||||
return &ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, GrantID: grantID, State: ProjectGrantStateActive}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectGrant) IsActive() bool {
|
|
||||||
return p.State == ProjectGrantStateActive
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectGrant) IsValid() bool {
|
|
||||||
return p.GrantedOrgID != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectGrant) GetMember(userID string) (int, *ProjectGrantMember) {
|
|
||||||
for i, m := range p.Members {
|
|
||||||
if m.UserID == userID {
|
|
||||||
return i, m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectGrant) GetRemovedRoles(roleKeys []string) []string {
|
|
||||||
removed := make([]string, 0)
|
|
||||||
for _, role := range p.RoleKeys {
|
|
||||||
if !containsKey(roleKeys, role) {
|
|
||||||
removed = append(removed, role)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return removed
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsKey(roles []string, key string) bool {
|
|
||||||
for _, role := range roles {
|
|
||||||
if role == key {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -8,11 +8,3 @@ type ProjectGrantMember struct {
|
|||||||
UserID string
|
UserID string
|
||||||
Roles []string
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProjectGrantMember(projectID, grantID, userID string) *ProjectGrantMember {
|
|
||||||
return &ProjectGrantMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, GrantID: grantID, UserID: userID}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectGrantMember) IsValid() bool {
|
|
||||||
return p.AggregateID != "" && p.UserID != "" && len(p.Roles) != 0
|
|
||||||
}
|
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectGrantMemberView struct {
|
|
||||||
UserID string
|
|
||||||
GrantID string
|
|
||||||
ProjectID string
|
|
||||||
UserName string
|
|
||||||
Email string
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
DisplayName string
|
|
||||||
PreferredLoginName string
|
|
||||||
AvatarURL string
|
|
||||||
UserResourceOwner string
|
|
||||||
Roles []string
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantMemberSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn ProjectGrantMemberSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*ProjectGrantMemberSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantMemberSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ProjectGrantMemberSearchKeyUnspecified ProjectGrantMemberSearchKey = iota
|
|
||||||
ProjectGrantMemberSearchKeyUserName
|
|
||||||
ProjectGrantMemberSearchKeyEmail
|
|
||||||
ProjectGrantMemberSearchKeyFirstName
|
|
||||||
ProjectGrantMemberSearchKeyLastName
|
|
||||||
ProjectGrantMemberSearchKeyGrantID
|
|
||||||
ProjectGrantMemberSearchKeyUserID
|
|
||||||
ProjectGrantMemberSearchKeyProjectID
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectGrantMemberSearchQuery struct {
|
|
||||||
Key ProjectGrantMemberSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantMemberSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*ProjectGrantMemberView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantMemberSearchRequest) EnsureLimit(limit uint64) error {
|
|
||||||
if r.Limit > limit {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "SEARCH-ZT8df", "Errors.Limit.ExceedsDefault")
|
|
||||||
}
|
|
||||||
if r.Limit == 0 {
|
|
||||||
r.Limit = limit
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectGrantView struct {
|
|
||||||
ProjectID string
|
|
||||||
Name string
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
State ProjectState
|
|
||||||
ResourceOwner string
|
|
||||||
ResourceOwnerName string
|
|
||||||
OrgID string
|
|
||||||
OrgName string
|
|
||||||
OrgDomain string
|
|
||||||
Sequence uint64
|
|
||||||
GrantID string
|
|
||||||
GrantedRoleKeys []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantViewSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn ProjectGrantViewSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*ProjectGrantViewSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantViewSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
GrantedProjectSearchKeyUnspecified ProjectGrantViewSearchKey = iota
|
|
||||||
GrantedProjectSearchKeyName
|
|
||||||
GrantedProjectSearchKeyProjectID
|
|
||||||
GrantedProjectSearchKeyGrantID
|
|
||||||
GrantedProjectSearchKeyOrgID
|
|
||||||
GrantedProjectSearchKeyResourceOwner
|
|
||||||
GrantedProjectSearchKeyRoleKeys
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectGrantViewSearchQuery struct {
|
|
||||||
Key ProjectGrantViewSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectGrantViewSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*ProjectGrantView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantViewSearchRequest) GetSearchQuery(key ProjectGrantViewSearchKey) (int, *ProjectGrantViewSearchQuery) {
|
|
||||||
for i, q := range r.Queries {
|
|
||||||
if q.Key == key {
|
|
||||||
return i, q
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantViewSearchRequest) AppendMyOrgQuery(orgID string) {
|
|
||||||
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyOrgID, Method: domain.SearchMethodEquals, Value: orgID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantViewSearchRequest) AppendNotMyOrgQuery(orgID string) {
|
|
||||||
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyOrgID, Method: domain.SearchMethodNotEquals, Value: orgID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantViewSearchRequest) AppendMyResourceOwnerQuery(orgID string) {
|
|
||||||
r.Queries = append(r.Queries, &ProjectGrantViewSearchQuery{Key: GrantedProjectSearchKeyResourceOwner, Method: domain.SearchMethodEquals, Value: orgID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectGrantViewSearchRequest) EnsureLimit(limit uint64) error {
|
|
||||||
if r.Limit > limit {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "SEARCH-0fj3s", "Errors.Limit.ExceedsDefault")
|
|
||||||
}
|
|
||||||
if r.Limit == 0 {
|
|
||||||
r.Limit = limit
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -8,11 +8,3 @@ type ProjectMember struct {
|
|||||||
UserID string
|
UserID string
|
||||||
Roles []string
|
Roles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProjectMember(projectID, userID string) *ProjectMember {
|
|
||||||
return &ProjectMember{ObjectRoot: es_models.ObjectRoot{AggregateID: projectID}, UserID: userID}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *ProjectMember) IsValid() bool {
|
|
||||||
return p.AggregateID != "" && p.UserID != "" && len(p.Roles) != 0
|
|
||||||
}
|
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectMemberView struct {
|
|
||||||
UserID string
|
|
||||||
ProjectID string
|
|
||||||
UserName string
|
|
||||||
Email string
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
DisplayName string
|
|
||||||
PreferredLoginName string
|
|
||||||
AvatarURL string
|
|
||||||
UserResourceOwner string
|
|
||||||
Roles []string
|
|
||||||
CreationDate time.Time
|
|
||||||
ChangeDate time.Time
|
|
||||||
Sequence uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectMemberSearchRequest struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
SortingColumn ProjectMemberSearchKey
|
|
||||||
Asc bool
|
|
||||||
Queries []*ProjectMemberSearchQuery
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectMemberSearchKey int32
|
|
||||||
|
|
||||||
const (
|
|
||||||
ProjectMemberSearchKeyUnspecified ProjectMemberSearchKey = iota
|
|
||||||
ProjectMemberSearchKeyUserName
|
|
||||||
ProjectMemberSearchKeyEmail
|
|
||||||
ProjectMemberSearchKeyFirstName
|
|
||||||
ProjectMemberSearchKeyLastName
|
|
||||||
ProjectMemberSearchKeyProjectID
|
|
||||||
ProjectMemberSearchKeyUserID
|
|
||||||
)
|
|
||||||
|
|
||||||
type ProjectMemberSearchQuery struct {
|
|
||||||
Key ProjectMemberSearchKey
|
|
||||||
Method domain.SearchMethod
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProjectMemberSearchResponse struct {
|
|
||||||
Offset uint64
|
|
||||||
Limit uint64
|
|
||||||
TotalResult uint64
|
|
||||||
Result []*ProjectMemberView
|
|
||||||
Sequence uint64
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ProjectMemberSearchRequest) EnsureLimit(limit uint64) error {
|
|
||||||
if r.Limit > limit {
|
|
||||||
return zerrors.ThrowInvalidArgument(nil, "SEARCH-389Nd", "Errors.Limit.ExceedsDefault")
|
|
||||||
}
|
|
||||||
if r.Limit == 0 {
|
|
||||||
r.Limit = limit
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (r *ProjectMemberSearchRequest) AppendProjectQuery(projectID string) {
|
|
||||||
r.Queries = append(r.Queries, &ProjectMemberSearchQuery{Key: ProjectMemberSearchKeyProjectID, Method: domain.SearchMethodEquals, Value: projectID})
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user