mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:57:31 +00:00
feat: token revocation and OP certification (#2594)
* fix: try using only user session if no user is set (id_token_hint) on prompt none * fix caos errors As implementation * implement request mode * return explicit error on invalid refresh token use * begin token revocation * token revocation * tests * tests * cleanup * set op config * add revocation endpoint to config * add revocation endpoint to config * migration version * error handling in token revocation * migration version * update oidc lib to 1.0.0
This commit is contained in:
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/caos/oidc/pkg/oidc"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
@@ -56,15 +55,13 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "error access token, error",
|
||||
name: "missing ID, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args: args{},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
err: caos_errs.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -73,8 +70,15 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "refreshTokenID1"),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
orgID: "orgID",
|
||||
agentID: "agentID",
|
||||
userID: "userID",
|
||||
clientID: "clientID",
|
||||
},
|
||||
args: args{},
|
||||
res: res{
|
||||
err: caos_errs.IsNotFound,
|
||||
},
|
||||
@@ -82,39 +86,7 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
{
|
||||
name: "renew refresh token, invalid token, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "accessTokenID1"),
|
||||
eventstore: eventstoreExpect(t),
|
||||
keyAlgorithm: refreshTokenEncryptionAlgorithm(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
@@ -128,39 +100,7 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
{
|
||||
name: "renew refresh token, invalid token (invalid userID), error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "accessTokenID1"),
|
||||
eventstore: eventstoreExpect(t),
|
||||
keyAlgorithm: refreshTokenEncryptionAlgorithm(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
@@ -177,36 +117,6 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
name: "renew refresh token, token inactive, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanRefreshTokenAddedEvent(
|
||||
context.Background(),
|
||||
@@ -229,7 +139,6 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "accessTokenID1"),
|
||||
keyAlgorithm: refreshTokenEncryptionAlgorithm(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
@@ -246,36 +155,6 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
name: "renew refresh token, token expired, error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanAddedEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("userID", "orgID").Aggregate,
|
||||
"username",
|
||||
"firstname",
|
||||
"lastname",
|
||||
"nickname",
|
||||
"displayname",
|
||||
language.German,
|
||||
domain.GenderUnspecified,
|
||||
"email",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(user.NewHumanRefreshTokenAddedEvent(
|
||||
context.Background(),
|
||||
@@ -293,7 +172,6 @@ func TestCommands_AddAccessAndRefreshToken(t *testing.T) {
|
||||
)),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "accessTokenID1"),
|
||||
keyAlgorithm: refreshTokenEncryptionAlgorithm(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
@@ -809,7 +687,6 @@ func TestCommands_addRefreshToken(t *testing.T) {
|
||||
authTime := time.Now().Add(-1 * time.Hour)
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
keyAlgorithm crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
@@ -836,7 +713,6 @@ func TestCommands_addRefreshToken(t *testing.T) {
|
||||
name: "add refresh Token",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "refreshTokenID"),
|
||||
keyAlgorithm: refreshTokenEncryptionAlgorithm(gomock.NewController(t)),
|
||||
},
|
||||
args: args{
|
||||
@@ -849,6 +725,7 @@ func TestCommands_addRefreshToken(t *testing.T) {
|
||||
TokenID: "accessTokenID1",
|
||||
ApplicationID: "clientID",
|
||||
UserAgentID: "agentID",
|
||||
RefreshTokenID: "refreshTokenID",
|
||||
Audience: []string{"clientID1"},
|
||||
Expiration: time.Now().Add(5 * time.Minute),
|
||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess},
|
||||
@@ -882,7 +759,6 @@ func TestCommands_addRefreshToken(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
keyAlgorithm: tt.fields.keyAlgorithm,
|
||||
}
|
||||
gotEvent, gotRefreshToken, err := c.addRefreshToken(tt.args.ctx, tt.args.accessToken, tt.args.authMethodsReferences, tt.args.authTime, tt.args.idleExpiration, tt.args.expiration)
|
||||
@@ -915,6 +791,7 @@ func TestCommands_renewRefreshToken(t *testing.T) {
|
||||
}
|
||||
type res struct {
|
||||
event *user.HumanRefreshTokenRenewedEvent
|
||||
refreshTokenID string
|
||||
newRefreshToken string
|
||||
err func(error) bool
|
||||
}
|
||||
@@ -1076,6 +953,7 @@ func TestCommands_renewRefreshToken(t *testing.T) {
|
||||
"refreshToken1",
|
||||
1*time.Hour,
|
||||
),
|
||||
refreshTokenID: "tokenID",
|
||||
newRefreshToken: base64.RawURLEncoding.EncodeToString([]byte("userID:tokenID:refreshToken1")),
|
||||
},
|
||||
},
|
||||
@@ -1087,7 +965,7 @@ func TestCommands_renewRefreshToken(t *testing.T) {
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
keyAlgorithm: tt.fields.keyAlgorithm,
|
||||
}
|
||||
gotEvent, gotNewRefreshToken, err := c.renewRefreshToken(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.refreshToken, tt.args.idleExpiration)
|
||||
gotEvent, gotRefreshTokenID, gotNewRefreshToken, err := c.renewRefreshToken(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.refreshToken, tt.args.idleExpiration)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -1096,6 +974,7 @@ func TestCommands_renewRefreshToken(t *testing.T) {
|
||||
}
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.event, gotEvent)
|
||||
assert.Equal(t, tt.res.refreshTokenID, gotRefreshTokenID)
|
||||
assert.Equal(t, tt.res.newRefreshToken, gotNewRefreshToken)
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user