mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-13 09:25:12 +00:00
feat(action v2): add JWT and JWE payload type options (#11196)
# Which Problems Are Solved The payload in actions V2 is currently sent as JSON to the target endpoint. It might get exposed to intermediary infrastructure or logging systems. For these scenarios there needs to be an application-layer encryption, where the provider of the endpoint can define an key to be used for the encryption. # How the Problems Are Solved - Added an additional option to the target to specify the payload type: `JSON` (current and default), `JWT`, `JWE` (api and console) - added endpoints to upload and manage public keys (to be used for encryption) for a target - updated all action v2 executions (interceptors, oidc, saml, ...) to provide the `GetActiveSigningWebKey` from queries - implemented jwt and jwe in the exections incl. refactoring of code and tests - changes to the authn_keys table: - added a `fingerprint` column - dropped not null constraint on expiration - moved the `GetSignerOnce` into its own package to prevent circular dependencies # Additional Changes None # Additional Context closes #11061 --------- Co-authored-by: Marco A. <[email protected]> Co-authored-by: conblem <[email protected]> Co-authored-by: Silvan <[email protected]>
This commit is contained in:
co-authored by
Marco A.
conblem
Silvan
parent
72c8f0192c
commit
791d0587aa
@@ -84,6 +84,10 @@ var (
|
||||
name: projection.AuthNKeyEnabledCol,
|
||||
table: authNKeyTable,
|
||||
}
|
||||
AuthNKeyColumnFingerprint = Column{
|
||||
name: projection.AuthNKeyFingerprintCol,
|
||||
table: authNKeyTable,
|
||||
}
|
||||
)
|
||||
|
||||
type AuthNKeys struct {
|
||||
@@ -100,8 +104,11 @@ type AuthNKey struct {
|
||||
Sequence uint64
|
||||
ApplicationID string
|
||||
|
||||
Expiration time.Time
|
||||
Type domain.AuthNKeyType
|
||||
Expiration time.Time
|
||||
Type domain.AuthNKeyType
|
||||
Enabled bool
|
||||
PublicKey []byte
|
||||
Fingerprint string
|
||||
}
|
||||
|
||||
type AuthNKeysData struct {
|
||||
@@ -141,6 +148,7 @@ const (
|
||||
JoinFilterUnspecified JoinFilter = iota
|
||||
JoinFilterApp
|
||||
JoinFilterUserMachine
|
||||
JoinFilterTarget
|
||||
)
|
||||
|
||||
// SearchAuthNKeys returns machine or app keys, depending on the join filter.
|
||||
@@ -173,11 +181,17 @@ func (q *Queries) searchAuthNKeys(ctx context.Context, queries *AuthNKeySearchQu
|
||||
case JoinFilterUserMachine:
|
||||
query = query.Join(join(MachineUserIDCol, AuthNKeyColumnIdentifier))
|
||||
query = userPermissionCheckV2WithCustomColumns(ctx, query, permissionCheckV2, queries.Queries, AuthNKeyColumnResourceOwner, AuthNKeyColumnIdentifier)
|
||||
case JoinFilterTarget:
|
||||
query = query.Join(join(TargetColumnID, AuthNKeyColumnObjectID))
|
||||
}
|
||||
eq := sq.Eq{
|
||||
AuthNKeyColumnEnabled.identifier(): true,
|
||||
AuthNKeyColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
}
|
||||
// Until now all disabled keys were just filtered out, but target keys can be explicitly disabled and
|
||||
// the state needs to be returned rather than filtering them out.
|
||||
if joinFilter != JoinFilterTarget {
|
||||
eq[AuthNKeyColumnEnabled.identifier()] = true
|
||||
}
|
||||
|
||||
stmt, args, err := query.Where(eq).ToSql()
|
||||
if err != nil {
|
||||
@@ -283,6 +297,14 @@ func NewAuthNKeyIDQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(AuthNKeyColumnID, id, TextEquals)
|
||||
}
|
||||
|
||||
func NewAuthNKeyInIDsSearchQuery(ids []string) (SearchQuery, error) {
|
||||
return NewInTextQuery(AuthNKeyColumnID, ids)
|
||||
}
|
||||
|
||||
func NewAuthNKeyEnabledSearchQuery(enabled bool) (SearchQuery, error) {
|
||||
return NewBoolQuery(AuthNKeyColumnEnabled, enabled)
|
||||
}
|
||||
|
||||
func NewAuthNKeyIdentifyerQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(AuthNKeyColumnIdentifier, id, TextEquals)
|
||||
}
|
||||
@@ -291,8 +313,19 @@ func NewAuthNKeyCreationDateQuery(ts time.Time, compare TimestampComparison) (Se
|
||||
return NewTimestampQuery(AuthNKeyColumnCreationDate, ts, compare)
|
||||
}
|
||||
|
||||
func NewAuthNKeyExpirationDateDateQuery(ts time.Time, compare TimestampComparison) (SearchQuery, error) {
|
||||
return NewTimestampQuery(AuthNKeyColumnExpiration, ts, compare)
|
||||
func NewAuthNKeyExpirationDateQuery(ts time.Time, compare TimestampComparison) (SearchQuery, error) {
|
||||
query, err := NewTimestampQuery(AuthNKeyColumnExpiration, ts, compare)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if compare != TimestampGreater && compare != TimestampGreaterOrEquals {
|
||||
return query, nil
|
||||
}
|
||||
noExpiration, err := NewIsNullQuery(AuthNKeyColumnExpiration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewOrQuery(query, noExpiration)
|
||||
}
|
||||
|
||||
//go:embed authn_key_user.sql
|
||||
@@ -344,6 +377,9 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys
|
||||
AuthNKeyColumnExpiration.identifier(),
|
||||
AuthNKeyColumnType.identifier(),
|
||||
AuthNKeyColumnObjectID.identifier(),
|
||||
AuthNKeyColumnEnabled.identifier(),
|
||||
AuthNKeyColumnPublicKey.identifier(),
|
||||
AuthNKeyColumnFingerprint.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(authNKeyTable.identifier()).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
@@ -352,6 +388,8 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys
|
||||
authNKeys := make([]*AuthNKey, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
var expiration sql.NullTime
|
||||
var fingerprint sql.NullString
|
||||
authNKey := new(AuthNKey)
|
||||
err := rows.Scan(
|
||||
&authNKey.ID,
|
||||
@@ -360,14 +398,23 @@ func prepareAuthNKeysQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys
|
||||
&authNKey.ChangeDate,
|
||||
&authNKey.ResourceOwner,
|
||||
&authNKey.Sequence,
|
||||
&authNKey.Expiration,
|
||||
&expiration,
|
||||
&authNKey.Type,
|
||||
&authNKey.ApplicationID,
|
||||
&authNKey.Enabled,
|
||||
&authNKey.PublicKey,
|
||||
&fingerprint,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if expiration.Valid {
|
||||
authNKey.Expiration = expiration.Time
|
||||
}
|
||||
if fingerprint.Valid {
|
||||
authNKey.Fingerprint = fingerprint.String
|
||||
}
|
||||
authNKeys = append(authNKeys, authNKey)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -27,6 +28,9 @@ var (
|
||||
` projections.authn_keys2.expiration,` +
|
||||
` projections.authn_keys2.type,` +
|
||||
` projections.authn_keys2.object_id,` +
|
||||
` projections.authn_keys2.enabled,` +
|
||||
` projections.authn_keys2.public_key,` +
|
||||
` projections.authn_keys2.fingerprint,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.authn_keys2`
|
||||
prepareAuthNKeysCols = []string{
|
||||
@@ -39,6 +43,9 @@ var (
|
||||
"expiration",
|
||||
"type",
|
||||
"object_id",
|
||||
"enabled",
|
||||
"public_key",
|
||||
"fingerprint",
|
||||
"count",
|
||||
}
|
||||
|
||||
@@ -132,6 +139,9 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
testNow,
|
||||
1,
|
||||
"app1",
|
||||
true,
|
||||
[]byte("public"),
|
||||
"fingerprint",
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -151,6 +161,9 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
Expiration: testNow,
|
||||
Type: domain.AuthNKeyTypeJSON,
|
||||
ApplicationID: "app1",
|
||||
Enabled: true,
|
||||
PublicKey: []byte("public"),
|
||||
Fingerprint: "fingerprint",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -173,6 +186,9 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
testNow,
|
||||
1,
|
||||
"app1",
|
||||
true,
|
||||
[]byte("public1"),
|
||||
"fingerprint1",
|
||||
},
|
||||
{
|
||||
"id-2",
|
||||
@@ -181,9 +197,12 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
testNow,
|
||||
"ro",
|
||||
uint64(20211109),
|
||||
testNow,
|
||||
nil,
|
||||
1,
|
||||
"app1",
|
||||
true,
|
||||
[]byte("public2"),
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -203,6 +222,9 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
Expiration: testNow,
|
||||
Type: domain.AuthNKeyTypeJSON,
|
||||
ApplicationID: "app1",
|
||||
Enabled: true,
|
||||
PublicKey: []byte("public1"),
|
||||
Fingerprint: "fingerprint1",
|
||||
},
|
||||
{
|
||||
ID: "id-2",
|
||||
@@ -211,9 +233,12 @@ func Test_AuthNKeyPrepares(t *testing.T) {
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
Sequence: 20211109,
|
||||
Expiration: testNow,
|
||||
Expiration: time.Time{},
|
||||
Type: domain.AuthNKeyTypeJSON,
|
||||
ApplicationID: "app1",
|
||||
Enabled: true,
|
||||
PublicKey: []byte("public2"),
|
||||
Fingerprint: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -35,7 +35,10 @@ with domain as (
|
||||
'endpoint', t.endpoint,
|
||||
'timeout', t.timeout,
|
||||
'interrupt_on_error', t.interrupt_on_error,
|
||||
'signing_key', t.signing_key
|
||||
'signing_key', t.signing_key,
|
||||
'payload_type', t.payload_type,
|
||||
'encryption_key', encode(k.public_key, 'base64'),
|
||||
'encryption_key_id', k.id
|
||||
) as execution_targets
|
||||
from domain d
|
||||
join projections.executions1 e
|
||||
@@ -46,6 +49,11 @@ with domain as (
|
||||
join projections.targets2 t
|
||||
on et.instance_id = t.instance_id
|
||||
and et.target_id = t.id
|
||||
left join projections.authn_keys2 k
|
||||
on k.instance_id = et.instance_id
|
||||
and k.object_id = t.id
|
||||
and k.enabled = true
|
||||
and (k.expiration IS NULL or k.expiration > now())
|
||||
order by et.position asc
|
||||
) as x
|
||||
group by instance_id
|
||||
|
||||
@@ -26,7 +26,10 @@ with features as (
|
||||
'endpoint', t.endpoint,
|
||||
'timeout', t.timeout,
|
||||
'interrupt_on_error', t.interrupt_on_error,
|
||||
'signing_key', t.signing_key
|
||||
'signing_key', t.signing_key,
|
||||
'payload_type', t.payload_type,
|
||||
'encryption_key', encode(k.public_key, 'base64'),
|
||||
'encryption_key_id', k.id
|
||||
) as execution_targets
|
||||
from projections.executions1 e
|
||||
join projections.executions1_targets et
|
||||
@@ -35,6 +38,11 @@ with features as (
|
||||
join projections.targets2 t
|
||||
on et.instance_id = t.instance_id
|
||||
and et.target_id = t.id
|
||||
left join projections.authn_keys2 k
|
||||
on k.instance_id = et.instance_id
|
||||
and k.object_id = t.id
|
||||
and k.enabled = true
|
||||
and (k.expiration IS NULL or k.expiration > now())
|
||||
where e.instance_id = $1
|
||||
order by et.position asc
|
||||
) as x
|
||||
|
||||
@@ -2,6 +2,7 @@ package projection
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/repository/target"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -30,6 +32,7 @@ const (
|
||||
AuthNKeyPublicKeyCol = "public_key"
|
||||
AuthNKeyTypeCol = "type"
|
||||
AuthNKeyEnabledCol = "enabled"
|
||||
AuthNKeyFingerprintCol = "fingerprint"
|
||||
)
|
||||
|
||||
type authNKeyProjection struct{}
|
||||
@@ -53,11 +56,12 @@ func (*authNKeyProjection) Init() *old_handler.Check {
|
||||
handler.NewColumn(AuthNKeyAggregateIDCol, handler.ColumnTypeText),
|
||||
handler.NewColumn(AuthNKeySequenceCol, handler.ColumnTypeInt64),
|
||||
handler.NewColumn(AuthNKeyObjectIDCol, handler.ColumnTypeText),
|
||||
handler.NewColumn(AuthNKeyExpirationCol, handler.ColumnTypeTimestamp),
|
||||
handler.NewColumn(AuthNKeyExpirationCol, handler.ColumnTypeTimestamp, handler.Nullable()),
|
||||
handler.NewColumn(AuthNKeyIdentifierCol, handler.ColumnTypeText),
|
||||
handler.NewColumn(AuthNKeyPublicKeyCol, handler.ColumnTypeBytes),
|
||||
handler.NewColumn(AuthNKeyEnabledCol, handler.ColumnTypeBool, handler.Default(true)),
|
||||
handler.NewColumn(AuthNKeyTypeCol, handler.ColumnTypeEnum, handler.Default(0)),
|
||||
handler.NewColumn(AuthNKeyFingerprintCol, handler.ColumnTypeText, handler.Nullable()),
|
||||
},
|
||||
handler.NewPrimaryKey(AuthNKeyInstanceIDCol, AuthNKeyIDCol),
|
||||
handler.WithIndex(handler.NewIndex("enabled", []string{AuthNKeyEnabledCol})),
|
||||
@@ -117,6 +121,31 @@ func (p *authNKeyProjection) Reducers() []handler.AggregateReducer {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: target.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: target.KeyAddedEventType,
|
||||
Reduce: p.reduceAuthNKeyAdded,
|
||||
},
|
||||
{
|
||||
Event: target.KeyActivatedEventType,
|
||||
Reduce: p.reduceTargetKeyActivated,
|
||||
},
|
||||
{
|
||||
Event: target.KeyDeactivatedEventType,
|
||||
Reduce: p.reduceTargetKeyDeactivated,
|
||||
},
|
||||
{
|
||||
Event: target.KeyRemovedEventType,
|
||||
Reduce: p.reduceAuthNKeyRemoved,
|
||||
},
|
||||
{
|
||||
Event: target.RemovedEventType,
|
||||
Reduce: p.reduceAuthNKeyRemoved,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
@@ -141,30 +170,43 @@ func (p *authNKeyProjection) Reducers() []handler.AggregateReducer {
|
||||
func (p *authNKeyProjection) reduceAuthNKeyAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||
var authNKeyEvent struct {
|
||||
eventstore.BaseEvent
|
||||
keyID string
|
||||
objectID string
|
||||
expiration time.Time
|
||||
identifier string
|
||||
publicKey []byte
|
||||
keyType domain.AuthNKeyType
|
||||
keyID string
|
||||
objectID string
|
||||
expiration sql.NullTime
|
||||
identifier string
|
||||
publicKey []byte
|
||||
keyType domain.AuthNKeyType
|
||||
fingerprint sql.NullString
|
||||
enabled bool
|
||||
}
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationKeyAddedEvent:
|
||||
authNKeyEvent.BaseEvent = e.BaseEvent
|
||||
authNKeyEvent.keyID = e.KeyID
|
||||
authNKeyEvent.objectID = e.AppID
|
||||
authNKeyEvent.expiration = e.ExpirationDate
|
||||
authNKeyEvent.expiration = sql.NullTime{Time: e.ExpirationDate, Valid: true}
|
||||
authNKeyEvent.identifier = e.ClientID
|
||||
authNKeyEvent.publicKey = e.PublicKey
|
||||
authNKeyEvent.keyType = e.KeyType
|
||||
authNKeyEvent.enabled = true
|
||||
case *user.MachineKeyAddedEvent:
|
||||
authNKeyEvent.BaseEvent = e.BaseEvent
|
||||
authNKeyEvent.keyID = e.KeyID
|
||||
authNKeyEvent.objectID = e.Aggregate().ID
|
||||
authNKeyEvent.expiration = e.ExpirationDate
|
||||
authNKeyEvent.expiration = sql.NullTime{Time: e.ExpirationDate, Valid: true}
|
||||
authNKeyEvent.identifier = e.Aggregate().ID
|
||||
authNKeyEvent.publicKey = e.PublicKey
|
||||
authNKeyEvent.keyType = e.KeyType
|
||||
authNKeyEvent.enabled = true
|
||||
case *target.KeyAddedEvent:
|
||||
authNKeyEvent.BaseEvent = e.BaseEvent
|
||||
authNKeyEvent.keyID = e.KeyID
|
||||
authNKeyEvent.objectID = e.Aggregate().ID
|
||||
authNKeyEvent.expiration = sql.NullTime{Time: e.ExpirationDate, Valid: !e.ExpirationDate.IsZero()}
|
||||
authNKeyEvent.identifier = e.Aggregate().ID
|
||||
authNKeyEvent.publicKey = e.PublicKey
|
||||
authNKeyEvent.fingerprint = sql.NullString{String: e.Fingerprint, Valid: true}
|
||||
authNKeyEvent.enabled = false
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "PROJE-Dgb32", "reduce.wrong.event.type %v", []eventstore.EventType{project.ApplicationKeyAddedEventType, user.MachineKeyAddedEventType})
|
||||
}
|
||||
@@ -183,6 +225,8 @@ func (p *authNKeyProjection) reduceAuthNKeyAdded(event eventstore.Event) (*handl
|
||||
handler.NewCol(AuthNKeyIdentifierCol, authNKeyEvent.identifier),
|
||||
handler.NewCol(AuthNKeyPublicKeyCol, authNKeyEvent.publicKey),
|
||||
handler.NewCol(AuthNKeyTypeCol, authNKeyEvent.keyType),
|
||||
handler.NewCol(AuthNKeyFingerprintCol, authNKeyEvent.fingerprint),
|
||||
handler.NewCol(AuthNKeyEnabledCol, authNKeyEvent.enabled),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
@@ -239,6 +283,10 @@ func (p *authNKeyProjection) reduceAuthNKeyRemoved(event eventstore.Event) (*han
|
||||
condition = handler.NewCond(AuthNKeyIDCol, e.KeyID)
|
||||
case *user.UserRemovedEvent:
|
||||
condition = handler.NewCond(AuthNKeyAggregateIDCol, e.Aggregate().ID)
|
||||
case *target.KeyRemovedEvent:
|
||||
condition = handler.NewCond(AuthNKeyIDCol, e.KeyID)
|
||||
case *target.RemovedEvent:
|
||||
condition = handler.NewCond(AuthNKeyAggregateIDCol, e.Aggregate().ID)
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "PROJE-BGge42", "reduce.wrong.event.type %v", []eventstore.EventType{project.ApplicationKeyRemovedEventType, project.ApplicationRemovedType, project.ProjectRemovedType, user.MachineKeyRemovedEventType, user.UserRemovedType})
|
||||
}
|
||||
@@ -265,3 +313,55 @@ func (p *authNKeyProjection) reduceOwnerRemoved(event eventstore.Event) (*handle
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *authNKeyProjection) reduceTargetKeyActivated(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, err := assertEvent[*target.KeyActivatedEvent](event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewMultiStatement(
|
||||
e,
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(AuthNKeyEnabledCol, false),
|
||||
handler.NewCol(AuthNKeyChangeDateCol, e.CreationDate()),
|
||||
handler.NewCol(AuthNKeySequenceCol, e.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AuthNKeyInstanceIDCol, e.Aggregate().InstanceID),
|
||||
handler.NewCond(AuthNKeyAggregateIDCol, e.Aggregate().ID),
|
||||
handler.NewCond(AuthNKeyEnabledCol, true),
|
||||
},
|
||||
),
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(AuthNKeyEnabledCol, true),
|
||||
handler.NewCol(AuthNKeyChangeDateCol, e.CreationDate()),
|
||||
handler.NewCol(AuthNKeySequenceCol, e.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AuthNKeyIDCol, e.KeyID),
|
||||
handler.NewCond(AuthNKeyInstanceIDCol, e.Aggregate().InstanceID),
|
||||
},
|
||||
),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (p *authNKeyProjection) reduceTargetKeyDeactivated(event eventstore.Event) (*handler.Statement, error) {
|
||||
e, err := assertEvent[*target.KeyDeactivatedEvent](event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpdateStatement(
|
||||
e,
|
||||
[]handler.Column{
|
||||
handler.NewCol(AuthNKeyEnabledCol, false),
|
||||
handler.NewCol(AuthNKeyChangeDateCol, e.CreationDate()),
|
||||
handler.NewCol(AuthNKeySequenceCol, e.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(AuthNKeyIDCol, e.KeyID),
|
||||
handler.NewCond(AuthNKeyInstanceIDCol, e.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/repository/target"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -40,7 +42,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type, fingerprint, enabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"keyId",
|
||||
anyArg{},
|
||||
@@ -54,6 +56,8 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
"clientId",
|
||||
[]byte("publicKey"),
|
||||
domain.AuthNKeyTypeJSON,
|
||||
sql.NullString{}, // fingerprint is not set for apps
|
||||
true, // apps keys are enabled by default
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -77,7 +81,7 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type, fingerprint, enabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"keyId",
|
||||
anyArg{},
|
||||
@@ -91,6 +95,47 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
"agg-id",
|
||||
[]byte("publicKey"),
|
||||
domain.AuthNKeyTypeJSON,
|
||||
sql.NullString{}, // fingerprint is not set for users
|
||||
true, // user keys are enabled by default
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceAuthNKeyAdded target",
|
||||
args: args{
|
||||
event: getEvent(
|
||||
testEvent(
|
||||
target.KeyAddedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"keyId": "keyId", "expirationDate": "2021-11-30T15:00:00Z", "publicKey": "cHVibGljS2V5", "fingerprint": "fingerprint"}`),
|
||||
), eventstore.GenericEventMapper[target.KeyAddedEvent]),
|
||||
},
|
||||
reduce: (&authNKeyProjection{}).reduceAuthNKeyAdded,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("target"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.authn_keys2 (id, creation_date, change_date, resource_owner, instance_id, aggregate_id, sequence, object_id, expiration, identifier, public_key, type, fingerprint, enabled) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
|
||||
expectedArgs: []interface{}{
|
||||
"keyId",
|
||||
anyArg{},
|
||||
anyArg{},
|
||||
"ro-id",
|
||||
"instance-id",
|
||||
"agg-id",
|
||||
uint64(15),
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
"agg-id",
|
||||
[]byte("publicKey"),
|
||||
domain.AuthNKeyTypeNONE,
|
||||
sql.NullString{String: "fingerprint", Valid: true},
|
||||
false, // target keys are disabled by default
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -470,6 +515,60 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceAuthNKeyRemoved target key removed",
|
||||
args: args{
|
||||
event: getEvent(
|
||||
testEvent(
|
||||
target.KeyRemovedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"keyId": "keyId"}`),
|
||||
), eventstore.GenericEventMapper[target.KeyRemovedEvent]),
|
||||
},
|
||||
reduce: (&authNKeyProjection{}).reduceAuthNKeyRemoved,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("target"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"keyId",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceAuthNKeyRemoved target removed",
|
||||
args: args{
|
||||
event: getEvent(
|
||||
testEvent(
|
||||
target.RemovedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"keyId": "keyId"}`),
|
||||
), eventstore.GenericEventMapper[target.RemovedEvent]),
|
||||
},
|
||||
reduce: (&authNKeyProjection{}).reduceAuthNKeyRemoved,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("target"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "DELETE FROM projections.authn_keys2 WHERE (aggregate_id = $1) AND (instance_id = $2)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceOwnerRemoved",
|
||||
args: args{
|
||||
@@ -497,6 +596,77 @@ func TestAuthNKeyProjection_reduces(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceTargetKeyActivated",
|
||||
args: args{
|
||||
event: getEvent(
|
||||
testEvent(
|
||||
target.KeyActivatedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"keyId": "keyId"}`),
|
||||
), eventstore.GenericEventMapper[target.KeyActivatedEvent]),
|
||||
},
|
||||
reduce: (&authNKeyProjection{}).reduceTargetKeyActivated,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("target"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.authn_keys2 SET (enabled, change_date, sequence) = ($1, $2, $3) WHERE (instance_id = $4) AND (aggregate_id = $5) AND (enabled = $6)",
|
||||
expectedArgs: []interface{}{
|
||||
false,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"instance-id",
|
||||
"agg-id",
|
||||
true,
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.authn_keys2 SET (enabled, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
true,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"keyId",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reduceTargetKeyDeactivated",
|
||||
args: args{
|
||||
event: getEvent(
|
||||
testEvent(
|
||||
target.KeyDeactivatedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"keyId": "keyId"}`),
|
||||
), eventstore.GenericEventMapper[target.KeyDeactivatedEvent]),
|
||||
},
|
||||
reduce: (&authNKeyProjection{}).reduceTargetKeyDeactivated,
|
||||
want: wantReduce{
|
||||
aggregateType: eventstore.AggregateType("target"),
|
||||
sequence: 15,
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.authn_keys2 SET (enabled, change_date, sequence) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||
expectedArgs: []interface{}{
|
||||
false,
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
"keyId",
|
||||
"instance-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
target_domain "github.com/zitadel/zitadel/internal/execution/target"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/target"
|
||||
)
|
||||
@@ -24,6 +25,7 @@ const (
|
||||
TargetTimeoutCol = "timeout"
|
||||
TargetInterruptOnErrorCol = "interrupt_on_error"
|
||||
TargetSigningKey = "signing_key"
|
||||
TargetPayloadType = "payload_type"
|
||||
)
|
||||
|
||||
type targetProjection struct{}
|
||||
@@ -51,6 +53,7 @@ func (*targetProjection) Init() *old_handler.Check {
|
||||
handler.NewColumn(TargetTimeoutCol, handler.ColumnTypeInt64),
|
||||
handler.NewColumn(TargetInterruptOnErrorCol, handler.ColumnTypeBool),
|
||||
handler.NewColumn(TargetSigningKey, handler.ColumnTypeJSONB, handler.Nullable()),
|
||||
handler.NewColumn(TargetPayloadType, handler.ColumnTypeEnum, handler.Default(target_domain.PayloadTypeUnspecified)),
|
||||
},
|
||||
handler.NewPrimaryKey(TargetInstanceIDCol, TargetIDCol),
|
||||
),
|
||||
@@ -108,6 +111,7 @@ func (p *targetProjection) reduceTargetAdded(event eventstore.Event) (*handler.S
|
||||
handler.NewCol(TargetTimeoutCol, e.Timeout),
|
||||
handler.NewCol(TargetInterruptOnErrorCol, e.InterruptOnError),
|
||||
handler.NewCol(TargetSigningKey, e.SigningKey),
|
||||
handler.NewCol(TargetPayloadType, e.PayloadType),
|
||||
},
|
||||
), nil
|
||||
}
|
||||
@@ -140,6 +144,9 @@ func (p *targetProjection) reduceTargetChanged(event eventstore.Event) (*handler
|
||||
if e.SigningKey != nil {
|
||||
values = append(values, handler.NewCol(TargetSigningKey, e.SigningKey))
|
||||
}
|
||||
if e.PayloadType != target_domain.PayloadTypeUnspecified {
|
||||
values = append(values, handler.NewCol(TargetPayloadType, e.PayloadType))
|
||||
}
|
||||
return handler.NewUpdateStatement(
|
||||
e,
|
||||
values,
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
testEvent(
|
||||
target.AddedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"name": "name", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true, "signingKey": { "cryptoType": 0, "algorithm": "RSA-265", "keyId": "key-id" }}`),
|
||||
[]byte(`{"name": "name", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true, "signingKey": { "cryptoType": 0, "algorithm": "RSA-265", "keyId": "key-id" }, "payloadType": 1}`),
|
||||
),
|
||||
eventstore.GenericEventMapper[target.AddedEvent],
|
||||
),
|
||||
@@ -41,7 +41,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.targets2 (instance_id, resource_owner, id, creation_date, change_date, sequence, name, endpoint, target_type, timeout, interrupt_on_error, signing_key) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
expectedStmt: "INSERT INTO projections.targets2 (instance_id, resource_owner, id, creation_date, change_date, sequence, name, endpoint, target_type, timeout, interrupt_on_error, signing_key, payload_type) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
|
||||
expectedArgs: []interface{}{
|
||||
"instance-id",
|
||||
"ro-id",
|
||||
@@ -55,6 +55,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
3 * time.Second,
|
||||
true,
|
||||
anyArg{},
|
||||
target_domain.PayloadTypeJSON,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -68,7 +69,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
testEvent(
|
||||
target.ChangedEventType,
|
||||
target.AggregateType,
|
||||
[]byte(`{"name": "name2", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true, "signingKey": { "cryptoType": 0, "algorithm": "RSA-265", "keyId": "key-id" }}`),
|
||||
[]byte(`{"name": "name2", "targetType":0, "endpoint":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true, "signingKey": { "cryptoType": 0, "algorithm": "RSA-265", "keyId": "key-id" }, "payloadType": 1}`),
|
||||
),
|
||||
eventstore.GenericEventMapper[target.ChangedEvent],
|
||||
),
|
||||
@@ -80,7 +81,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPDATE projections.targets2 SET (change_date, sequence, resource_owner, name, target_type, endpoint, timeout, interrupt_on_error, signing_key) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (instance_id = $10) AND (id = $11)",
|
||||
expectedStmt: "UPDATE projections.targets2 SET (change_date, sequence, resource_owner, name, target_type, endpoint, timeout, interrupt_on_error, signing_key, payload_type) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) WHERE (instance_id = $11) AND (id = $12)",
|
||||
expectedArgs: []interface{}{
|
||||
anyArg{},
|
||||
uint64(15),
|
||||
@@ -91,6 +92,7 @@ func TestTargetProjection_reduces(t *testing.T) {
|
||||
3 * time.Second,
|
||||
true,
|
||||
anyArg{},
|
||||
target_domain.PayloadTypeJSON,
|
||||
"instance-id",
|
||||
"agg-id",
|
||||
},
|
||||
|
||||
@@ -65,6 +65,10 @@ var (
|
||||
name: projection.TargetSigningKey,
|
||||
table: targetTable,
|
||||
}
|
||||
TargetColumnPayloadType = Column{
|
||||
name: projection.TargetPayloadType,
|
||||
table: targetTable,
|
||||
}
|
||||
)
|
||||
|
||||
type Targets struct {
|
||||
@@ -86,6 +90,7 @@ type Target struct {
|
||||
InterruptOnError bool
|
||||
signingKey *crypto.CryptoValue
|
||||
SigningKey string
|
||||
PayloadType target_domain.PayloadType
|
||||
}
|
||||
|
||||
func (t *Target) decryptSigningKey(alg crypto.EncryptionAlgorithm) error {
|
||||
@@ -166,6 +171,7 @@ func prepareTargetsQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*Targets, er
|
||||
TargetColumnURL.identifier(),
|
||||
TargetColumnInterruptOnError.identifier(),
|
||||
TargetColumnSigningKey.identifier(),
|
||||
TargetColumnPayloadType.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(targetTable.identifier()).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
@@ -185,6 +191,7 @@ func prepareTargetsQuery() (sq.SelectBuilder, func(rows *sql.Rows) (*Targets, er
|
||||
&target.Endpoint,
|
||||
&target.InterruptOnError,
|
||||
&target.signingKey,
|
||||
&target.PayloadType,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -218,6 +225,7 @@ func prepareTargetQuery() (sq.SelectBuilder, func(row *sql.Row) (*Target, error)
|
||||
TargetColumnURL.identifier(),
|
||||
TargetColumnInterruptOnError.identifier(),
|
||||
TargetColumnSigningKey.identifier(),
|
||||
TargetColumnPayloadType.identifier(),
|
||||
).From(targetTable.identifier()).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Target, error) {
|
||||
@@ -233,6 +241,7 @@ func prepareTargetQuery() (sq.SelectBuilder, func(row *sql.Row) (*Target, error)
|
||||
&target.Endpoint,
|
||||
&target.InterruptOnError,
|
||||
&target.signingKey,
|
||||
&target.PayloadType,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
|
||||
@@ -26,6 +26,7 @@ var (
|
||||
` projections.targets2.endpoint,` +
|
||||
` projections.targets2.interrupt_on_error,` +
|
||||
` projections.targets2.signing_key,` +
|
||||
` projections.targets2.payload_type,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.targets2`
|
||||
prepareTargetsCols = []string{
|
||||
@@ -39,6 +40,7 @@ var (
|
||||
"endpoint",
|
||||
"interrupt_on_error",
|
||||
"signing_key",
|
||||
"payload_type",
|
||||
"count",
|
||||
}
|
||||
|
||||
@@ -51,7 +53,8 @@ var (
|
||||
` projections.targets2.timeout,` +
|
||||
` projections.targets2.endpoint,` +
|
||||
` projections.targets2.interrupt_on_error,` +
|
||||
` projections.targets2.signing_key` +
|
||||
` projections.targets2.signing_key,` +
|
||||
` projections.targets2.payload_type` +
|
||||
` FROM projections.targets2`
|
||||
prepareTargetCols = []string{
|
||||
"id",
|
||||
@@ -64,6 +67,7 @@ var (
|
||||
"endpoint",
|
||||
"interrupt_on_error",
|
||||
"signing_key",
|
||||
"payload_type",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -114,6 +118,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
target_domain.PayloadTypeJSON,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -141,6 +146,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
PayloadType: target_domain.PayloadTypeJSON,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -169,6 +175,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
target_domain.PayloadTypeJSON,
|
||||
},
|
||||
{
|
||||
"id-2",
|
||||
@@ -186,6 +193,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
target_domain.PayloadTypeJWT,
|
||||
},
|
||||
{
|
||||
"id-3",
|
||||
@@ -203,6 +211,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
target_domain.PayloadTypeJWE,
|
||||
},
|
||||
},
|
||||
),
|
||||
@@ -230,6 +239,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
PayloadType: target_domain.PayloadTypeJSON,
|
||||
},
|
||||
{
|
||||
ObjectDetails: domain.ObjectDetails{
|
||||
@@ -249,6 +259,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
PayloadType: target_domain.PayloadTypeJWT,
|
||||
},
|
||||
{
|
||||
ObjectDetails: domain.ObjectDetails{
|
||||
@@ -268,6 +279,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
PayloadType: target_domain.PayloadTypeJWE,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -330,6 +342,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
target_domain.PayloadTypeJSON,
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -351,6 +364,7 @@ func Test_TargetPrepares(t *testing.T) {
|
||||
KeyID: "encKey",
|
||||
Crypted: []byte("crypted"),
|
||||
},
|
||||
PayloadType: target_domain.PayloadTypeJSON,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user