fix: access tokens for service users and refresh token infos (#1779)

* fix: access token for service user

* handle info from refresh request

* uniqueness

* postpone access token uniqueness change
This commit is contained in:
Livio Amstutz 2021-05-26 09:01:07 +02:00 committed by GitHub
parent 070abae6d9
commit bf4c4d881d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 46 additions and 21 deletions

View File

@ -110,17 +110,7 @@ func grantsToScopes(grants []*grant_model.UserGrantView) []string {
func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.TokenRequest, refreshToken string) (_, _ string, _ time.Time, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
var userAgentID, applicationID, userOrgID string
var authTime time.Time
var authMethodsReferences []string
authReq, ok := req.(*AuthRequest)
if ok {
userAgentID = authReq.AgentID
applicationID = authReq.ApplicationID
userOrgID = authReq.UserOrgID
authTime = authReq.AuthTime
authMethodsReferences = authReq.GetAMR()
}
userAgentID, applicationID, userOrgID, authTime, authMethodsReferences := getInfoFromRequest(req)
resp, token, err := o.command.AddAccessAndRefreshToken(ctx, userOrgID, userAgentID, applicationID, req.GetSubject(),
refreshToken, req.GetAudience(), req.GetScopes(), authMethodsReferences, o.defaultAccessTokenLifetime,
o.defaultRefreshTokenIdleExpiration, o.defaultRefreshTokenExpiration, authTime) //PLANNED: lifetime from client
@ -130,6 +120,18 @@ func (o *OPStorage) CreateAccessAndRefreshTokens(ctx context.Context, req op.Tok
return resp.TokenID, token, resp.Expiration, nil
}
func getInfoFromRequest(req op.TokenRequest) (string, string, string, time.Time, []string) {
authReq, ok := req.(*AuthRequest)
if ok {
return authReq.AgentID, authReq.ApplicationID, authReq.UserOrgID, authReq.AuthTime, authReq.GetAMR()
}
refreshReq, ok := req.(*RefreshTokenRequest)
if ok {
return refreshReq.UserAgentID, refreshReq.ClientID, "", refreshReq.AuthTime, refreshReq.AuthMethodsReferences
}
return "", "", "", time.Time{}, nil
}
func (o *OPStorage) TokenRequestByRefreshToken(ctx context.Context, refreshToken string) (op.RefreshTokenRequest, error) {
tokenView, err := o.repo.RefreshTokenByID(ctx, refreshToken)
if err != nil {

View File

@ -211,7 +211,7 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
}
func (c *Commands) AddUserToken(ctx context.Context, orgID, agentID, clientID, userID string, audience, scopes []string, lifetime time.Duration) (*domain.Token, error) {
if orgID == "" || userID == "" {
if userID == "" { //do not check for empty orgID (JWT Profile requests won't provide it, so service user requests fail)
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Dbge4", "Errors.IDMissing")
}
userWriteModel := NewUserWriteModel(userID, orgID)

View File

@ -24,14 +24,14 @@ const (
)
type RefreshTokenView struct {
ID string `json:"tokenId" gorm:"column:id"`
ID string `json:"tokenId" gorm:"column:id;primary_key"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
Token string `json:"-" gorm:"column:token"`
UserID string `json:"-" gorm:"column:user_id;primary_key"`
ClientID string `json:"clientID" gorm:"column:client_id;primary_key"`
UserAgentID string `json:"userAgentId" gorm:"column:user_agent_id;primary_key"`
UserID string `json:"-" gorm:"column:user_id"`
ClientID string `json:"clientID" gorm:"column:client_id"`
UserAgentID string `json:"userAgentId" gorm:"column:user_agent_id"`
Audience pq.StringArray `json:"audience" gorm:"column:audience"`
Scopes pq.StringArray `json:"scopes" gorm:"column:scopes"`
AuthMethodsReferences pq.StringArray `json:"authMethodsReference" gorm:"column:amr"`

View File

@ -1,13 +1,14 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/lib/pq"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/user/model"
usr_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
"github.com/jinzhu/gorm"
"github.com/lib/pq"
)
func RefreshTokenByID(db *gorm.DB, table, tokenID string) (*usr_model.RefreshTokenView, error) {
@ -35,7 +36,10 @@ func RefreshTokensByUserID(db *gorm.DB, table, userID string) ([]*usr_model.Refr
}
func PutRefreshToken(db *gorm.DB, table string, token *usr_model.RefreshTokenView) error {
save := repository.PrepareSave(table)
save := repository.PrepareSaveOnConflict(table,
[]string{"client_id", "user_agent_id", "user_id"},
[]string{"id", "creation_date", "change_date", "token", "auth_time", "idle_expiration", "expiration", "sequence", "scopes", "audience", "amr"},
)
return save(db, token)
}

View File

@ -1,13 +1,14 @@
package view
import (
"github.com/jinzhu/gorm"
"github.com/lib/pq"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/user/model"
usr_model "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository"
"github.com/jinzhu/gorm"
"github.com/lib/pq"
)
func TokenByID(db *gorm.DB, table, tokenID string) (*usr_model.TokenView, error) {

View File

@ -3,6 +3,7 @@ package repository
import (
"errors"
"fmt"
"strings"
"github.com/caos/logging"
"github.com/jinzhu/gorm"
@ -80,6 +81,21 @@ func PrepareSave(table string) func(db *gorm.DB, object interface{}) error {
}
}
func PrepareSaveOnConflict(table string, conflictColumns, updateColumns []string) func(db *gorm.DB, object interface{}) error {
updates := make([]string, len(updateColumns))
for i, column := range updateColumns {
updates[i] = column + "=excluded." + column
}
onConflict := fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET %s", strings.Join(conflictColumns, ","), strings.Join(updates, ","))
return func(db *gorm.DB, object interface{}) error {
err := db.Table(table).Set("gorm:insert_option", onConflict).Save(object).Error
if err != nil {
return caos_errs.ThrowInternal(err, "VIEW-AfC7G", "unable to put object to view")
}
return nil
}
}
func PrepareDeleteByKey(table string, key ColumnKey, id interface{}) func(db *gorm.DB) error {
return func(db *gorm.DB) error {
err := db.Table(table).

View File

@ -0,0 +1,2 @@
ALTER TABLE auth.refresh_tokens ALTER COLUMN id SET NOT NULL;
ALTER TABLE auth.refresh_tokens ALTER PRIMARY KEY USING COLUMNS(id);