Merge branch 'main' into next-rc

This commit is contained in:
adlerhurst 2024-01-02 16:28:37 +01:00
commit 76c84d385c
138 changed files with 1021 additions and 6427 deletions

View File

@ -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:

View File

@ -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
View File

@ -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
View 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
View File

@ -0,0 +1 @@
CREATE INDEX CONCURRENTLY IF NOT EXISTS events2_current_sequence ON eventstore.events2 ("sequence" DESC, aggregate_id, aggregate_type, instance_id);

View File

@ -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 {

View File

@ -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)

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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 {

View File

@ -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:

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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:

View File

@ -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{

View File

@ -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 {

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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()
} }

View File

@ -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)
}

View File

@ -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
} }

View File

@ -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)
}
})
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -1,5 +0,0 @@
package cache
type Config interface {
NewCache() (Cache, error)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}
})
}
}

View File

@ -1,3 +0,0 @@
package cache
//go:generate mockgen -package mock -destination ./mock/cache.mock.go github.com/zitadel/zitadel/internal/cache Cache

View File

@ -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)
}

View File

@ -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]
}
}
}

View File

@ -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
}

View File

@ -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
} }

View File

@ -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 (

View File

@ -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
} }

View File

@ -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
}

View File

@ -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
}

View File

@ -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 (

View File

@ -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
} }

View File

@ -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
}

View File

@ -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
)

View File

@ -1,9 +0,0 @@
package domain
type UniqueConstraintMigration struct {
AggregateID string
ObjectID string
UniqueType string
UniqueField string
ErrorMessage string
}

View File

@ -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])

View File

@ -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
)

View File

@ -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,

View File

@ -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",

View File

@ -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;

View File

@ -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
}

View File

@ -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
}

View File

@ -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 ""
}
}

View File

@ -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}})
}

View File

@ -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})
}

View File

@ -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 != ""
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 != ""
}

View File

@ -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 != ""
}

View File

@ -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
}

View File

@ -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})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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))
}
})
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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 ""
}
}

View File

@ -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
}

View File

@ -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 ""
}
}

View File

@ -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)
} }

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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))
}
})
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
})
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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