mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 19:44:21 +00:00
fix: translation (#647)
* fix: translation * fix: translation * fix: translation * fix: remove unused code * fix: log err
This commit is contained in:
parent
34ec2508d3
commit
7295383621
@ -43,7 +43,7 @@ func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *Tok
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userID, clientID, agentID, err := verifyAccessToken(ctx, token, t, method)
|
userID, clientID, agentID, prefLang, err := verifyAccessToken(ctx, token, t, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *Tok
|
|||||||
if err := checkOrigin(ctx, origins); err != nil {
|
if err := checkOrigin(ctx, origins); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID}), nil
|
return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID, PreferredLanguage: prefLang}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
|
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
|
||||||
|
@ -15,8 +15,8 @@ type testVerifier struct {
|
|||||||
grant *Grant
|
grant *Grant
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, error) {
|
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) {
|
||||||
return "userID", "agentID", nil
|
return "userID", "agentID", "de", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) {
|
func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) {
|
||||||
|
@ -19,7 +19,7 @@ type TokenVerifier struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type authZRepo interface {
|
type authZRepo interface {
|
||||||
VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID string, err error)
|
VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID, prefLang string, err error)
|
||||||
VerifierClientID(ctx context.Context, name string) (clientID string, err error)
|
VerifierClientID(ctx context.Context, name string) (clientID string, err error)
|
||||||
ResolveGrants(ctx context.Context) (grant *Grant, err error)
|
ResolveGrants(ctx context.Context) (grant *Grant, err error)
|
||||||
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
|
ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error)
|
||||||
@ -30,13 +30,13 @@ func Start(authZRepo authZRepo) (v *TokenVerifier) {
|
|||||||
return &TokenVerifier{authZRepo: authZRepo}
|
return &TokenVerifier{authZRepo: authZRepo}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID string, err error) {
|
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID, prefLang string, err error) {
|
||||||
clientID, err = v.clientIDFromMethod(ctx, method)
|
clientID, err = v.clientIDFromMethod(ctx, method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", "", err
|
return "", "", "", "", err
|
||||||
}
|
}
|
||||||
userID, agentID, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID)
|
userID, agentID, prefLang, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID)
|
||||||
return userID, clientID, agentID, err
|
return userID, clientID, agentID, prefLang, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
@ -101,10 +101,10 @@ func (v *TokenVerifier) CheckAuthMethod(method string) (Option, bool) {
|
|||||||
return authOpt, ok
|
return authOpt, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID string, err error) {
|
func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID, prefLang string, err error) {
|
||||||
parts := strings.Split(token, BearerPrefix)
|
parts := strings.Split(token, BearerPrefix)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header")
|
return "", "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header")
|
||||||
}
|
}
|
||||||
return t.VerifyAccessToken(ctx, parts[1], method)
|
return t.VerifyAccessToken(ctx, parts[1], method)
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ func Test_VerifyAccessToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
_, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method)
|
_, _, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method)
|
||||||
if tt.wantErr && err == nil {
|
if tt.wantErr && err == nil {
|
||||||
t.Errorf("got wrong result, should get err: actual: %v ", err)
|
t.Errorf("got wrong result, should get err: actual: %v ", err)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package grpc
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/i18n"
|
|
||||||
"github.com/caos/zitadel/pkg/grpc/message"
|
"github.com/caos/zitadel/pkg/grpc/message"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CaosToGRPCError(ctx context.Context, err error, translator *i18n.Translator) error {
|
func CaosToGRPCError(ctx context.Context, err error) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -19,10 +18,8 @@ func CaosToGRPCError(ctx context.Context, err error, translator *i18n.Translator
|
|||||||
return status.Convert(err).Err()
|
return status.Convert(err).Err()
|
||||||
}
|
}
|
||||||
msg := key
|
msg := key
|
||||||
if translator != nil {
|
|
||||||
msg = translator.LocalizeFromCtx(ctx, key, nil)
|
|
||||||
msg += " (" + id + ")"
|
msg += " (" + id + ")"
|
||||||
}
|
|
||||||
s, err := status.New(code, msg).WithDetails(&message.ErrorDetail{Id: id, Message: key})
|
s, err := status.New(code, msg).WithDetails(&message.ErrorDetail{Id: id, Message: key})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log("GRPC-gIeRw").WithError(err).Debug("unable to add detail")
|
logging.Log("GRPC-gIeRw").WithError(err).Debug("unable to add detail")
|
@ -1,4 +1,4 @@
|
|||||||
package grpc
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -8,13 +8,11 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
"github.com/caos/zitadel/internal/i18n"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCaosToGRPCError(t *testing.T) {
|
func TestCaosToGRPCError(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
err error
|
err error
|
||||||
translator *i18n.Translator
|
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -28,18 +26,18 @@ func TestCaosToGRPCError(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unknown error",
|
"unknown error",
|
||||||
args{errors.New("unknown"), nil},
|
args{errors.New("unknown")},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"caos error",
|
"caos error",
|
||||||
args{caos_errs.ThrowInternal(nil, "", "message"), nil},
|
args{caos_errs.ThrowInternal(nil, "", "message")},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if err := CaosToGRPCError(context.Background(), tt.args.err, tt.args.translator); (err != nil) != tt.wantErr {
|
if err := CaosToGRPCError(context.Background(), tt.args.err); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("CaosToGRPCError() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("CaosToGRPCError() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -21,8 +21,8 @@ var (
|
|||||||
|
|
||||||
type verifierMock struct{}
|
type verifierMock struct{}
|
||||||
|
|
||||||
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, error) {
|
func (v *verifierMock) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, string, error) {
|
||||||
return "", "", nil
|
return "", "", "", nil
|
||||||
}
|
}
|
||||||
func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) {
|
func (v *verifierMock) ResolveGrants(ctx context.Context) (*authz.Grant, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -2,24 +2,20 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/caos/zitadel/internal/api/grpc/errors"
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
grpc_util "github.com/caos/zitadel/internal/api/grpc"
|
|
||||||
"github.com/caos/zitadel/internal/i18n"
|
|
||||||
_ "github.com/caos/zitadel/internal/statik"
|
_ "github.com/caos/zitadel/internal/statik"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ErrorHandler(defaultLanguage language.Tag) grpc.UnaryServerInterceptor {
|
func ErrorHandler() grpc.UnaryServerInterceptor {
|
||||||
translator := newZitadelTranslator(defaultLanguage)
|
|
||||||
|
|
||||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
return toGRPCError(ctx, req, handler, translator)
|
return toGRPCError(ctx, req, handler)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toGRPCError(ctx context.Context, req interface{}, handler grpc.UnaryHandler, translator *i18n.Translator) (interface{}, error) {
|
func toGRPCError(ctx context.Context, req interface{}, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
resp, err := handler(ctx, req)
|
resp, err := handler(ctx, req)
|
||||||
return resp, grpc_util.CaosToGRPCError(ctx, err, translator)
|
return resp, errors.CaosToGRPCError(ctx, err)
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ func Test_toGRPCError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := toGRPCError(tt.args.ctx, tt.args.req, tt.args.handler, nil)
|
got, err := toGRPCError(tt.args.ctx, tt.args.req, tt.args.handler)
|
||||||
if (err != nil) != tt.res.wantErr {
|
if (err != nil) != tt.res.wantErr {
|
||||||
t.Errorf("toGRPCError() error = %v, wantErr %v", err, tt.res.wantErr)
|
t.Errorf("toGRPCError() error = %v, wantErr %v", err, tt.res.wantErr)
|
||||||
return
|
return
|
||||||
|
@ -18,6 +18,9 @@ func TranslationHandler(defaultLanguage language.Tag) func(ctx context.Context,
|
|||||||
if loc, ok := resp.(localizers); ok && resp != nil {
|
if loc, ok := resp.(localizers); ok && resp != nil {
|
||||||
translateFields(ctx, loc, translator)
|
translateFields(ctx, loc, translator)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = translateError(ctx, err, translator)
|
||||||
|
}
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"github.com/caos/zitadel/internal/i18n"
|
"github.com/caos/zitadel/internal/i18n"
|
||||||
@ -26,6 +28,17 @@ func translateFields(ctx context.Context, object localizers, translator *i18n.Tr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func translateError(ctx context.Context, err error, translator *i18n.Translator) error {
|
||||||
|
if translator == nil || err == nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
caosErr := new(caos_errs.CaosError)
|
||||||
|
if errors.As(err, &caosErr) {
|
||||||
|
caosErr.SetMessage(translator.LocalizeFromCtx(ctx, caosErr.GetMessage(), nil))
|
||||||
|
}
|
||||||
|
return caosErr
|
||||||
|
}
|
||||||
|
|
||||||
func newZitadelTranslator(defaultLanguage language.Tag) *i18n.Translator {
|
func newZitadelTranslator(defaultLanguage language.Tag) *i18n.Translator {
|
||||||
return translatorFromNamespace("zitadel", defaultLanguage)
|
return translatorFromNamespace("zitadel", defaultLanguage)
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,13 @@ func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang l
|
|||||||
middleware.TracingStatsServer(http.Healthz, http.Readiness, http.Validation),
|
middleware.TracingStatsServer(http.Healthz, http.Readiness, http.Validation),
|
||||||
grpc.UnaryInterceptor(
|
grpc.UnaryInterceptor(
|
||||||
grpc_middleware.ChainUnaryServer(
|
grpc_middleware.ChainUnaryServer(
|
||||||
middleware.ErrorHandler(lang),
|
middleware.ErrorHandler(),
|
||||||
middleware.TranslationHandler(lang),
|
|
||||||
grpc_middleware.ChainUnaryServer(
|
|
||||||
middleware.AuthorizationInterceptor(verifier, authConfig),
|
middleware.AuthorizationInterceptor(verifier, authConfig),
|
||||||
),
|
middleware.TranslationHandler(lang),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Serve(ctx context.Context, server *grpc.Server, port string) {
|
func Serve(ctx context.Context, server *grpc.Server, port string) {
|
||||||
|
@ -2,6 +2,8 @@ package oidc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
"github.com/caos/oidc/pkg/oidc"
|
"github.com/caos/oidc/pkg/oidc"
|
||||||
"github.com/caos/oidc/pkg/op"
|
"github.com/caos/oidc/pkg/op"
|
||||||
@ -78,6 +80,8 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, sc
|
|||||||
userInfo.PreferredUsername = user.PreferredLoginName
|
userInfo.PreferredUsername = user.PreferredLoginName
|
||||||
userInfo.UpdatedAt = user.ChangeDate
|
userInfo.UpdatedAt = user.ChangeDate
|
||||||
userInfo.Gender = oidc.Gender(getGender(user.Gender))
|
userInfo.Gender = oidc.Gender(getGender(user.Gender))
|
||||||
|
userInfo.Locale, err = language.Parse(user.PreferredLanguage)
|
||||||
|
logging.Log("OIDC-4ks9F").OnError(err).Debug("unable to parse locale")
|
||||||
case scopePhone:
|
case scopePhone:
|
||||||
userInfo.PhoneNumber = user.Phone
|
userInfo.PhoneNumber = user.Phone
|
||||||
userInfo.PhoneNumberVerified = user.IsPhoneVerified
|
userInfo.PhoneNumberVerified = user.IsPhoneVerified
|
||||||
|
@ -14,7 +14,12 @@ type TokenRepo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) {
|
func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) {
|
||||||
token, err := repo.View.CreateToken(agentID, applicationID, userID, audience, scopes, lifetime)
|
preferredLanguage := ""
|
||||||
|
user, _ := repo.View.UserByID(userID)
|
||||||
|
if user != nil {
|
||||||
|
preferredLanguage = user.PreferredLanguage
|
||||||
|
}
|
||||||
|
token, err := repo.View.CreateToken(agentID, applicationID, userID, preferredLanguage, audience, scopes, lifetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
|
||||||
@ -43,6 +44,17 @@ func (u *Token) EventQuery() (*models.SearchQuery, error) {
|
|||||||
|
|
||||||
func (u *Token) Reduce(event *models.Event) (err error) {
|
func (u *Token) Reduce(event *models.Event) (err error) {
|
||||||
switch event.Type {
|
switch event.Type {
|
||||||
|
case user_es_model.UserProfileChanged:
|
||||||
|
user := new(view_model.UserView)
|
||||||
|
user.AppendEvent(event)
|
||||||
|
tokens, err := u.view.TokensByUserID(event.AggregateID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, token := range tokens {
|
||||||
|
token.PreferredLanguage = user.PreferredLanguage
|
||||||
|
}
|
||||||
|
return u.view.PutTokens(tokens, event.Sequence)
|
||||||
case user_es_model.SignedOut:
|
case user_es_model.SignedOut:
|
||||||
id, err := agentIDFromSession(event)
|
id, err := agentIDFromSession(event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -16,11 +16,15 @@ func (v *View) TokenByID(tokenID string) (*model.Token, error) {
|
|||||||
return view.TokenByID(v.Db, tokenTable, tokenID)
|
return view.TokenByID(v.Db, tokenTable, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) TokensByUserID(userID string) ([]*model.Token, error) {
|
||||||
|
return view.TokensByUserID(v.Db, tokenTable, userID)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) IsTokenValid(tokenID string) (bool, error) {
|
func (v *View) IsTokenValid(tokenID string) (bool, error) {
|
||||||
return view.IsTokenValid(v.Db, tokenTable, tokenID)
|
return view.IsTokenValid(v.Db, tokenTable, tokenID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *View) CreateToken(agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) {
|
func (v *View) CreateToken(agentID, applicationID, userID, preferredLanguage string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) {
|
||||||
id, err := v.idGenerator.Next()
|
id, err := v.idGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -35,6 +39,7 @@ func (v *View) CreateToken(agentID, applicationID, userID string, audience, scop
|
|||||||
Scopes: scopes,
|
Scopes: scopes,
|
||||||
Audience: audience,
|
Audience: audience,
|
||||||
Expiration: now.Add(lifetime),
|
Expiration: now.Add(lifetime),
|
||||||
|
PreferredLanguage: preferredLanguage,
|
||||||
}
|
}
|
||||||
if err := view.PutToken(v.Db, tokenTable, token); err != nil {
|
if err := view.PutToken(v.Db, tokenTable, token); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -50,6 +55,14 @@ func (v *View) PutToken(token *model.Token) error {
|
|||||||
return v.ProcessedTokenSequence(token.Sequence)
|
return v.ProcessedTokenSequence(token.Sequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) PutTokens(token []*model.Token, sequence uint64) error {
|
||||||
|
err := view.PutTokens(v.Db, tokenTable, token...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return v.ProcessedTokenSequence(sequence)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
|
func (v *View) DeleteToken(tokenID string, eventSequence uint64) error {
|
||||||
err := view.DeleteToken(v.Db, tokenTable, tokenID)
|
err := view.DeleteToken(v.Db, tokenTable, tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,26 +19,26 @@ type TokenVerifierRepo struct {
|
|||||||
View *view.View
|
View *view.View
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, err error) {
|
func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, clientID string) (userID string, agentID string, prefLang string, err error) {
|
||||||
//TODO: use real key
|
//TODO: use real key
|
||||||
tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32]))
|
tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token")
|
return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-8EF0zZ", "invalid token")
|
||||||
}
|
}
|
||||||
token, err := repo.View.TokenByID(tokenID)
|
token, err := repo.View.TokenByID(tokenID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token")
|
return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-BxUSiL", "invalid token")
|
||||||
}
|
}
|
||||||
if !token.Expiration.After(time.Now().UTC()) {
|
if !token.Expiration.After(time.Now().UTC()) {
|
||||||
return "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token")
|
return "", "", "", caos_errs.ThrowUnauthenticated(err, "APP-k9KS0", "invalid token")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, aud := range token.Audience {
|
for _, aud := range token.Audience {
|
||||||
if clientID == aud {
|
if clientID == aud {
|
||||||
return token.UserID, token.UserAgentID, nil
|
return token.UserID, token.UserAgentID, token.PreferredLanguage, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience")
|
return "", "", "", caos_errs.ThrowUnauthenticated(nil, "APP-Zxfako", "invalid audience")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) {
|
func (repo *TokenVerifierRepo) ProjectIDAndOriginsByClientID(ctx context.Context, clientID string) (projectID string, origins []string, err error) {
|
||||||
|
@ -44,6 +44,10 @@ func (err *CaosError) GetMessage() string {
|
|||||||
return err.Message
|
return err.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (err *CaosError) SetMessage(msg string) {
|
||||||
|
err.Message = msg
|
||||||
|
}
|
||||||
|
|
||||||
func (err *CaosError) GetID() string {
|
func (err *CaosError) GetID() string {
|
||||||
return err.ID
|
return err.ID
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
type Error interface {
|
type Error interface {
|
||||||
GetParent() error
|
GetParent() error
|
||||||
GetMessage() string
|
GetMessage() string
|
||||||
|
SetMessage(string)
|
||||||
GetID() string
|
GetID() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
|
"github.com/grpc-ecosystem/go-grpc-middleware/util/metautils"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -130,6 +131,10 @@ func (t *Translator) langsFromRequest(r *http.Request) []string {
|
|||||||
func (t *Translator) langsFromCtx(ctx context.Context) []string {
|
func (t *Translator) langsFromCtx(ctx context.Context) []string {
|
||||||
langs := make([]string, 0)
|
langs := make([]string, 0)
|
||||||
if ctx != nil {
|
if ctx != nil {
|
||||||
|
ctxData := authz.GetCtxData(ctx)
|
||||||
|
if ctxData.PreferredLanguage != "" {
|
||||||
|
langs = append(langs, authz.GetCtxData(ctx).PreferredLanguage)
|
||||||
|
}
|
||||||
langs = append(langs, getAcceptLanguageHeader(ctx))
|
langs = append(langs, getAcceptLanguageHeader(ctx))
|
||||||
}
|
}
|
||||||
return langs
|
return langs
|
||||||
|
@ -18,6 +18,7 @@ type Token struct {
|
|||||||
Expiration time.Time
|
Expiration time.Time
|
||||||
Scopes []string
|
Scopes []string
|
||||||
Sequence uint64
|
Sequence uint64
|
||||||
|
PreferredLanguage string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenSearchRequest struct {
|
type TokenSearchRequest struct {
|
||||||
|
@ -29,6 +29,7 @@ type Token struct {
|
|||||||
Scopes pq.StringArray `json:"-" gorm:"column:scopes"`
|
Scopes pq.StringArray `json:"-" gorm:"column:scopes"`
|
||||||
Expiration time.Time `json:"-" gorm:"column:expiration"`
|
Expiration time.Time `json:"-" gorm:"column:expiration"`
|
||||||
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
Sequence uint64 `json:"-" gorm:"column:sequence"`
|
||||||
|
PreferredLanguage string `json:"-" gorm:"column:preferred_language"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TokenFromModel(token *model.Token) *Token {
|
func TokenFromModel(token *model.Token) *Token {
|
||||||
@ -44,6 +45,7 @@ func TokenFromModel(token *model.Token) *Token {
|
|||||||
Scopes: token.Scopes,
|
Scopes: token.Scopes,
|
||||||
Expiration: token.Expiration,
|
Expiration: token.Expiration,
|
||||||
Sequence: token.Sequence,
|
Sequence: token.Sequence,
|
||||||
|
PreferredLanguage: token.PreferredLanguage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,5 +62,6 @@ func TokenToModel(token *Token) *model.Token {
|
|||||||
Scopes: token.Scopes,
|
Scopes: token.Scopes,
|
||||||
Expiration: token.Expiration,
|
Expiration: token.Expiration,
|
||||||
Sequence: token.Sequence,
|
Sequence: token.Sequence,
|
||||||
|
PreferredLanguage: token.PreferredLanguage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package view
|
package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
global_model "github.com/caos/zitadel/internal/model"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
@ -22,6 +23,20 @@ func TokenByID(db *gorm.DB, table, tokenID string) (*model.Token, error) {
|
|||||||
return token, err
|
return token, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TokensByUserID(db *gorm.DB, table, userID string) ([]*model.Token, error) {
|
||||||
|
tokens := make([]*model.Token, 0)
|
||||||
|
userIDQuery := &token_model.TokenSearchQuery{
|
||||||
|
Key: token_model.TokenSearchKeyUserID,
|
||||||
|
Method: global_model.SearchMethodEquals,
|
||||||
|
Value: userID,
|
||||||
|
}
|
||||||
|
query := repository.PrepareSearchQuery(table, model.TokenSearchRequest{
|
||||||
|
Queries: []*token_model.TokenSearchQuery{userIDQuery},
|
||||||
|
})
|
||||||
|
_, err := query(db, &tokens)
|
||||||
|
return tokens, err
|
||||||
|
}
|
||||||
|
|
||||||
func IsTokenValid(db *gorm.DB, table, tokenID string) (bool, error) {
|
func IsTokenValid(db *gorm.DB, table, tokenID string) (bool, error) {
|
||||||
token, err := TokenByID(db, table, tokenID)
|
token, err := TokenByID(db, table, tokenID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -38,6 +53,15 @@ func PutToken(db *gorm.DB, table string, token *model.Token) error {
|
|||||||
return save(db, token)
|
return save(db, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PutTokens(db *gorm.DB, table string, tokens ...*model.Token) error {
|
||||||
|
save := repository.PrepareBulkSave(table)
|
||||||
|
t := make([]interface{}, len(tokens))
|
||||||
|
for i, token := range tokens {
|
||||||
|
t[i] = token
|
||||||
|
}
|
||||||
|
return save(db, t...)
|
||||||
|
}
|
||||||
|
|
||||||
func DeleteToken(db *gorm.DB, table, tokenID string) error {
|
func DeleteToken(db *gorm.DB, table, tokenID string) error {
|
||||||
delete := repository.PrepareDeleteByKey(table, model.TokenSearchKey(token_model.TokenSearchKeyTokenID), tokenID)
|
delete := repository.PrepareDeleteByKey(table, model.TokenSearchKey(token_model.TokenSearchKeyTokenID), tokenID)
|
||||||
return delete(db)
|
return delete(db)
|
||||||
|
@ -2,11 +2,11 @@ package tracing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
errors2 "github.com/caos/zitadel/internal/api/grpc/errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"go.opencensus.io/trace"
|
"go.opencensus.io/trace"
|
||||||
|
|
||||||
"github.com/caos/zitadel/internal/api/grpc"
|
|
||||||
"github.com/caos/zitadel/internal/errors"
|
"github.com/caos/zitadel/internal/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ func (s *Span) SetStatusByError(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func statusFromError(err error) trace.Status {
|
func statusFromError(err error) trace.Status {
|
||||||
code, msg, _, _ := grpc.ExtractCaosError(err)
|
code, msg, _, _ := errors2.ExtractCaosError(err)
|
||||||
return trace.Status{Code: int32(code), Message: msg}
|
return trace.Status{Code: int32(code), Message: msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
migrations/cockroach/V1.8__token.sql
Normal file
2
migrations/cockroach/V1.8__token.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
ALTER TABLE auth.tokens ADD COLUMN preferred_language TEXT;
|
Loading…
Reference in New Issue
Block a user