feat: port reduction (#323)

* move mgmt pkg

* begin package restructure

* rename auth package to authz

* begin start api

* move auth

* move admin

* fix merge

* configs and interceptors

* interceptor

* revert generate-grpc.sh

* some cleanups

* console

* move console

* fix tests and merging

* js linting

* merge

* merging and configs

* change k8s base to current ports

* fixes

* cleanup

* regenerate proto

* remove unnecessary whitespace

* missing param

* go mod tidy

* fix merging

* move login pkg

* cleanup

* move api pkgs again

* fix pkg naming

* fix generate-static.sh for login

* update workflow

* fixes

* logging

* remove duplicate

* comment for optional gateway interfaces

* regenerate protos

* fix proto imports for grpc web

* protos

* grpc web generate

* grpc web generate

* fix changes

* add translation interceptor

* fix merging

* regenerate mgmt proto
This commit is contained in:
Livio Amstutz
2020-07-08 13:56:37 +02:00
committed by GitHub
parent 708652a655
commit 3549a8b64e
330 changed files with 30495 additions and 30809 deletions

View File

@@ -0,0 +1,110 @@
package authz
import (
"context"
"fmt"
"reflect"
"strings"
"github.com/caos/zitadel/internal/errors"
)
const (
authenticated = "authenticated"
)
func CheckUserAuthorization(ctx context.Context, req interface{}, token, orgID string, verifier *TokenVerifier, authConfig Config, requiredAuthOption Option, method string) (context.Context, error) {
ctx, err := VerifyTokenAndWriteCtxData(ctx, token, orgID, verifier, method)
if err != nil {
return nil, err
}
var perms []string
if requiredAuthOption.Permission == authenticated {
return ctx, nil
}
ctx, perms, err = getUserMethodPermissions(ctx, verifier, requiredAuthOption.Permission, authConfig)
if err != nil {
return nil, err
}
err = checkUserPermissions(req, perms, requiredAuthOption)
if err != nil {
return nil, err
}
return ctx, nil
}
func checkUserPermissions(req interface{}, userPerms []string, authOpt Option) error {
if len(userPerms) == 0 {
return errors.ThrowPermissionDenied(nil, "AUTH-5mWD2", "No matching permissions found")
}
if authOpt.CheckParam == "" {
return nil
}
if HasGlobalPermission(userPerms) {
return nil
}
if hasContextPermission(req, authOpt.CheckParam, userPerms) {
return nil
}
return errors.ThrowPermissionDenied(nil, "AUTH-3jknH", "No matching permissions found")
}
func SplitPermission(perm string) (string, string) {
splittedPerm := strings.Split(perm, ":")
if len(splittedPerm) == 1 {
return splittedPerm[0], ""
}
return splittedPerm[0], splittedPerm[1]
}
func hasContextPermission(req interface{}, fieldName string, permissions []string) bool {
for _, perm := range permissions {
_, ctxID := SplitPermission(perm)
if checkPermissionContext(req, fieldName, ctxID) {
return true
}
}
return false
}
func checkPermissionContext(req interface{}, fieldName, roleContextID string) bool {
field := getFieldFromReq(req, fieldName)
return field != "" && field == roleContextID
}
func getFieldFromReq(req interface{}, field string) string {
v := reflect.Indirect(reflect.ValueOf(req)).FieldByName(field)
if reflect.ValueOf(v).IsZero() {
return ""
}
return fmt.Sprintf("%v", v.Interface())
}
func HasGlobalPermission(perms []string) bool {
for _, perm := range perms {
_, ctxID := SplitPermission(perm)
if ctxID == "" {
return true
}
}
return false
}
func GetPermissionCtxIDs(perms []string) []string {
ctxIDs := make([]string, 0)
for _, perm := range perms {
_, ctxID := SplitPermission(perm)
if ctxID != "" {
ctxIDs = append(ctxIDs, ctxID)
}
}
return ctxIDs
}

View File

@@ -0,0 +1,278 @@
package authz
import (
"testing"
"github.com/caos/zitadel/internal/errors"
)
type TestRequest struct {
Test string
}
func Test_CheckUserPermissions(t *testing.T) {
type args struct {
req *TestRequest
perms []string
authOpt Option
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "no permissions",
args: args{
req: &TestRequest{},
perms: []string{},
},
wantErr: true,
},
{
name: "has permission and no context requested",
args: args{
req: &TestRequest{},
perms: []string{"project.read"},
authOpt: Option{CheckParam: ""},
},
wantErr: false,
},
{
name: "context requested and has global permission",
args: args{
req: &TestRequest{Test: "Test"},
perms: []string{"project.read", "project.read:1"},
authOpt: Option{CheckParam: "Test"},
},
wantErr: false,
},
{
name: "context requested and has specific permission",
args: args{
req: &TestRequest{Test: "Test"},
perms: []string{"project.read:Test"},
authOpt: Option{CheckParam: "Test"},
},
wantErr: false,
},
{
name: "context requested and has no permission",
args: args{
req: &TestRequest{Test: "Hodor"},
perms: []string{"project.read:Test"},
authOpt: Option{CheckParam: "Test"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := checkUserPermissions(tt.args.req, tt.args.perms, tt.args.authOpt)
if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err)
}
if !tt.wantErr && err != nil {
t.Errorf("shouldn't get err: %v ", err)
}
if tt.wantErr && !errors.IsPermissionDenied(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func Test_SplitPermission(t *testing.T) {
type args struct {
perm string
}
tests := []struct {
name string
args args
permName string
permCtxID string
}{
{
name: "permission with context id",
args: args{
perm: "project.read:ctxID",
},
permName: "project.read",
permCtxID: "ctxID",
},
{
name: "permission without context id",
args: args{
perm: "project.read",
},
permName: "project.read",
permCtxID: "",
},
{
name: "permission to many parts",
args: args{
perm: "project.read:1:0",
},
permName: "project.read",
permCtxID: "1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
name, id := SplitPermission(tt.args.perm)
if name != tt.permName {
t.Errorf("got wrong result on name, expecting: %v, actual: %v ", tt.permName, name)
}
if id != tt.permCtxID {
t.Errorf("got wrong result on id, expecting: %v, actual: %v ", tt.permCtxID, id)
}
})
}
}
func Test_HasContextPermission(t *testing.T) {
type args struct {
req *TestRequest
fieldname string
perms []string
}
tests := []struct {
name string
args args
result bool
}{
{
name: "existing context permission",
args: args{
req: &TestRequest{Test: "right"},
fieldname: "Test",
perms: []string{"test:wrong", "test:right"},
},
result: true,
},
{
name: "not existing context permission",
args: args{
req: &TestRequest{Test: "test"},
fieldname: "Test",
perms: []string{"test:wrong", "test:wrong2"},
},
result: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := hasContextPermission(tt.args.req, tt.args.fieldname, tt.args.perms)
if result != tt.result {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_GetFieldFromReq(t *testing.T) {
type args struct {
req *TestRequest
fieldname string
}
tests := []struct {
name string
args args
result string
}{
{
name: "existing field",
args: args{
req: &TestRequest{Test: "TestValue"},
fieldname: "Test",
},
result: "TestValue",
},
{
name: "not existing field",
args: args{
req: &TestRequest{Test: "TestValue"},
fieldname: "Test2",
},
result: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := getFieldFromReq(tt.args.req, tt.args.fieldname)
if result != tt.result {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_HasGlobalPermission(t *testing.T) {
type args struct {
perms []string
}
tests := []struct {
name string
args args
result bool
}{
{
name: "global perm existing",
args: args{
perms: []string{"perm:1", "perm:2", "perm"},
},
result: true,
},
{
name: "global perm not existing",
args: args{
perms: []string{"perm:1", "perm:2", "perm:3"},
},
result: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := HasGlobalPermission(tt.args.perms)
if result != tt.result {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_GetPermissionCtxIDs(t *testing.T) {
type args struct {
perms []string
}
tests := []struct {
name string
args args
result []string
}{
{
name: "no specific permission",
args: args{
perms: []string{"perm"},
},
result: []string{},
},
{
name: "ctx id",
args: args{
perms: []string{"perm:1", "perm", "perm:3"},
},
result: []string{"1", "3"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := GetPermissionCtxIDs(tt.args.perms)
if !equalStringArray(result, tt.result) {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}

View File

@@ -0,0 +1,26 @@
package authz
type Config struct {
RolePermissionMappings []RoleMapping
}
type RoleMapping struct {
Role string
Permissions []string
}
type MethodMapping map[string]Option
type Option struct {
Permission string
CheckParam string
}
func (a *Config) getPermissionsFromRole(role string) []string {
for _, roleMap := range a.RolePermissionMappings {
if roleMap.Role == role {
return roleMap.Permissions
}
}
return nil
}

View File

@@ -0,0 +1,57 @@
package authz
import (
"context"
"github.com/caos/logging"
)
type key int
const (
permissionsKey key = 1
dataKey key = 2
)
type CtxData struct {
UserID string
OrgID string
ProjectID string
AgentID string
PreferredLanguage string
}
func (ctxData CtxData) IsZero() bool {
return ctxData.UserID == "" || ctxData.OrgID == ""
}
type Grants []*Grant
type Grant struct {
OrgID string
Roles []string
}
func VerifyTokenAndWriteCtxData(ctx context.Context, token, orgID string, t *TokenVerifier, method string) (_ context.Context, err error) {
userID, clientID, agentID, err := verifyAccessToken(ctx, token, t, method)
if err != nil {
return nil, err
}
projectID, err := t.GetProjectIDByClientID(ctx, clientID)
logging.LogWithFields("AUTH-GfAoV", "clientID", clientID).OnError(err).Warn("could not read projectid by clientid")
return context.WithValue(ctx, dataKey, CtxData{UserID: userID, OrgID: orgID, ProjectID: projectID, AgentID: agentID}), nil
}
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
return context.WithValue(ctx, dataKey, ctxData)
}
func GetCtxData(ctx context.Context) CtxData {
ctxData, _ := ctx.Value(dataKey).(CtxData)
return ctxData
}
func GetPermissionsFromCtx(ctx context.Context) []string {
ctxPermission, _ := ctx.Value(permissionsKey).([]string)
return ctxPermission
}

View File

@@ -0,0 +1,7 @@
package authz
import "context"
func NewMockContext(orgID, userID string) context.Context {
return context.WithValue(nil, dataKey, CtxData{UserID: userID, OrgID: orgID})
}

View File

@@ -0,0 +1,63 @@
package authz
import (
"context"
"github.com/caos/zitadel/internal/errors"
)
func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (context.Context, []string, error) {
ctxData := GetCtxData(ctx)
if ctxData.IsZero() {
return nil, nil, errors.ThrowUnauthenticated(nil, "AUTH-rKLWEH", "context missing")
}
grant, err := t.ResolveGrant(ctx)
if err != nil {
return nil, nil, err
}
if grant == nil {
return context.WithValue(ctx, permissionsKey, []string{}), []string{}, nil
}
permissions := mapGrantToPermissions(requiredPerm, grant, authConfig)
return context.WithValue(ctx, permissionsKey, permissions), permissions, nil
}
func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig Config) []string {
resolvedPermissions := make([]string, 0)
for _, role := range grant.Roles {
resolvedPermissions = mapRoleToPerm(requiredPerm, role, authConfig, resolvedPermissions)
}
return resolvedPermissions
}
func mapRoleToPerm(requiredPerm, actualRole string, authConfig Config, resolvedPermissions []string) []string {
roleName, roleContextID := SplitPermission(actualRole)
perms := authConfig.getPermissionsFromRole(roleName)
for _, p := range perms {
if p == requiredPerm {
p = addRoleContextIDToPerm(p, roleContextID)
if !ExistsPerm(resolvedPermissions, p) {
resolvedPermissions = append(resolvedPermissions, p)
}
}
}
return resolvedPermissions
}
func addRoleContextIDToPerm(perm, roleContextID string) string {
if roleContextID != "" {
perm = perm + ":" + roleContextID
}
return perm
}
func ExistsPerm(existing []string, perm string) bool {
for _, e := range existing {
if e == perm {
return true
}
}
return false
}

View File

@@ -0,0 +1,430 @@
package authz
import (
"context"
"testing"
caos_errs "github.com/caos/zitadel/internal/errors"
)
func getTestCtx(userID, orgID string) context.Context {
return context.WithValue(context.Background(), dataKey, CtxData{UserID: userID, OrgID: orgID})
}
type testVerifier struct {
grant *Grant
}
func (v *testVerifier) VerifyAccessToken(ctx context.Context, token, clientID string) (string, string, error) {
return "userID", "agentID", nil
}
func (v *testVerifier) ResolveGrants(ctx context.Context) (*Grant, error) {
return v.grant, nil
}
func (v *testVerifier) ProjectIDByClientID(ctx context.Context, clientID string) (string, error) {
return "", nil
}
func (v *testVerifier) VerifierClientID(ctx context.Context, appName string) (string, error) {
return "clientID", nil
}
func equalStringArray(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
func Test_GetUserMethodPermissions(t *testing.T) {
type args struct {
ctx context.Context
verifier *TokenVerifier
requiredPerm string
authConfig Config
}
tests := []struct {
name string
args args
wantErr bool
errFunc func(err error) bool
result []string
}{
{
name: "Empty Context",
args: args{
ctx: getTestCtx("", ""),
verifier: Start(&testVerifier{grant: &Grant{
Roles: []string{"ORG_OWNER"},
}}),
requiredPerm: "project.read",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
wantErr: true,
errFunc: caos_errs.IsUnauthenticated,
result: []string{"project.read"},
},
{
name: "No Grants",
args: args{
ctx: getTestCtx("", ""),
verifier: Start(&testVerifier{grant: &Grant{}}),
requiredPerm: "project.read",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: make([]string, 0),
},
{
name: "Get Permissions",
args: args{
ctx: getTestCtx("userID", "orgID"),
verifier: Start(&testVerifier{grant: &Grant{
Roles: []string{"ORG_OWNER"},
}}),
requiredPerm: "project.read",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: []string{"project.read"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, perms, err := getUserMethodPermissions(tt.args.ctx, tt.args.verifier, tt.args.requiredPerm, tt.args.authConfig)
if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err)
}
if tt.wantErr && !tt.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
if !tt.wantErr && !equalStringArray(perms, tt.result) {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, perms)
}
})
}
}
func Test_MapGrantsToPermissions(t *testing.T) {
type args struct {
requiredPerm string
grant *Grant
authConfig Config
}
tests := []struct {
name string
args args
result []string
}{
{
name: "One Role existing perm",
args: args{
requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER"}},
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: []string{"project.read"},
},
{
name: "One Role not existing perm",
args: args{
requiredPerm: "project.write",
grant: &Grant{Roles: []string{"ORG_OWNER"}},
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: []string{},
},
{
name: "Multiple Roles one existing",
args: args{
requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER", "IAM_OWNER"}},
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: []string{"project.read"},
},
{
name: "Multiple Roles, global and specific",
args: args{
requiredPerm: "project.read",
grant: &Grant{Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}},
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "PROJECT_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
},
result: []string{"project.read", "project.read:1"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := mapGrantToPermissions(tt.args.requiredPerm, tt.args.grant, tt.args.authConfig)
if !equalStringArray(result, tt.result) {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_MapRoleToPerm(t *testing.T) {
type args struct {
requiredPerm string
actualRole string
authConfig Config
resolvedPermissions []string
}
tests := []struct {
name string
args args
result []string
}{
{
name: "first perm without context id",
args: args{
requiredPerm: "project.read",
actualRole: "ORG_OWNER",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
resolvedPermissions: []string{},
},
result: []string{"project.read"},
},
{
name: "existing perm without context id",
args: args{
requiredPerm: "project.read",
actualRole: "ORG_OWNER",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "IAM_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
resolvedPermissions: []string{"project.read"},
},
result: []string{"project.read"},
},
{
name: "first perm with context id",
args: args{
requiredPerm: "project.read",
actualRole: "PROJECT_OWNER:1",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "PROJECT_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
resolvedPermissions: []string{},
},
result: []string{"project.read:1"},
},
{
name: "perm with context id, existing global",
args: args{
requiredPerm: "project.read",
actualRole: "PROJECT_OWNER:1",
authConfig: Config{
RolePermissionMappings: []RoleMapping{
{
Role: "PROJECT_OWNER",
Permissions: []string{"project.read"},
},
{
Role: "ORG_OWNER",
Permissions: []string{"org.read", "project.read"},
},
},
},
resolvedPermissions: []string{"project.read"},
},
result: []string{"project.read", "project.read:1"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := mapRoleToPerm(tt.args.requiredPerm, tt.args.actualRole, tt.args.authConfig, tt.args.resolvedPermissions)
if !equalStringArray(result, tt.result) {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_AddRoleContextIDToPerm(t *testing.T) {
type args struct {
perm string
ctxID string
}
tests := []struct {
name string
args args
result string
}{
{
name: "with ctx id",
args: args{
perm: "perm1",
ctxID: "2",
},
result: "perm1:2",
},
{
name: "with ctx id",
args: args{
perm: "perm1",
ctxID: "",
},
result: "perm1",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := addRoleContextIDToPerm(tt.args.perm, tt.args.ctxID)
if result != tt.result {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}
func Test_ExistisPerm(t *testing.T) {
type args struct {
existing []string
perm string
}
tests := []struct {
name string
args args
result bool
}{
{
name: "not existing perm",
args: args{
existing: []string{"perm1", "perm2", "perm3"},
perm: "perm4",
},
result: false,
},
{
name: "existing perm",
args: args{
existing: []string{"perm1", "perm2", "perm3"},
perm: "perm2",
},
result: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ExistsPerm(tt.args.existing, tt.args.perm)
if result != tt.result {
t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result)
}
})
}
}

105
internal/api/authz/token.go Normal file
View File

@@ -0,0 +1,105 @@
package authz
import (
"context"
"strings"
"sync"
caos_errs "github.com/caos/zitadel/internal/errors"
)
const (
BearerPrefix = "Bearer "
)
type TokenVerifier struct {
authZRepo authZRepo
clients sync.Map
authMethods MethodMapping
}
type authZRepo interface {
VerifyAccessToken(ctx context.Context, token, clientID string) (userID, agentID string, err error)
VerifierClientID(ctx context.Context, name string) (clientID string, err error)
ResolveGrants(ctx context.Context) (grant *Grant, err error)
ProjectIDByClientID(ctx context.Context, clientID string) (projectID string, err error)
}
func Start(authZRepo authZRepo) (v *TokenVerifier) {
return &TokenVerifier{authZRepo: authZRepo}
}
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string, method string) (userID, clientID, agentID string, err error) {
clientID, err = v.clientIDFromMethod(ctx, method)
if err != nil {
return "", "", "", err
}
userID, agentID, err = v.authZRepo.VerifyAccessToken(ctx, token, clientID)
return userID, clientID, agentID, err
}
type client struct {
id string
name string
}
func (v *TokenVerifier) RegisterServer(appName, methodPrefix string, mappings MethodMapping) {
v.clients.Store(methodPrefix, &client{name: appName})
if v.authMethods == nil {
v.authMethods = make(map[string]Option)
}
for method, option := range mappings {
v.authMethods[method] = option
}
}
func prefixFromMethod(method string) (string, bool) {
parts := strings.Split(method, "/")
if len(parts) < 2 {
return "", false
}
return parts[1], true
}
func (v *TokenVerifier) clientIDFromMethod(ctx context.Context, method string) (string, error) {
prefix, ok := prefixFromMethod(method)
if !ok {
return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-GRD2Q", "Errors.Internal")
}
app, ok := v.clients.Load(prefix)
if !ok {
return "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-G2qrh", "Errors.Internal")
}
var err error
c := app.(*client)
if c.id != "" {
return c.id, nil
}
c.id, err = v.authZRepo.VerifierClientID(ctx, c.name)
if err != nil {
return "", caos_errs.ThrowPermissionDenied(err, "AUTHZ-ptTIF2", "Errors.Internal")
}
v.clients.Store(prefix, c)
return c.id, nil
}
func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*Grant, error) {
return v.authZRepo.ResolveGrants(ctx)
}
func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) {
return v.authZRepo.ProjectIDByClientID(ctx, clientID)
}
func (v *TokenVerifier) CheckAuthMethod(method string) (Option, bool) {
authOpt, ok := v.authMethods[method]
return authOpt, ok
}
func verifyAccessToken(ctx context.Context, token string, t *TokenVerifier, method string) (userID, clientID, agentID string, err error) {
parts := strings.Split(token, BearerPrefix)
if len(parts) != 2 {
return "", "", "", caos_errs.ThrowUnauthenticated(nil, "AUTH-7fs1e", "invalid auth header")
}
return t.VerifyAccessToken(ctx, parts[1], method)
}

View File

@@ -0,0 +1,75 @@
package authz
import (
"context"
"sync"
"testing"
"github.com/caos/zitadel/internal/errors"
)
func Test_VerifyAccessToken(t *testing.T) {
type args struct {
ctx context.Context
token string
verifier *TokenVerifier
method string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "no auth header set",
args: args{
ctx: context.Background(),
token: "",
},
wantErr: true,
},
{
name: "wrong auth header set",
args: args{
ctx: context.Background(),
token: "Basic sds",
},
wantErr: true,
},
{
name: "auth header set",
args: args{
ctx: context.Background(),
token: "Bearer AUTH",
verifier: &TokenVerifier{
authZRepo: &testVerifier{grant: &Grant{}},
clients: func() sync.Map {
m := sync.Map{}
m.Store("service", &client{name: "name"})
return m
}(),
authMethods: MethodMapping{"/service/method": Option{Permission: "authenticated"}},
},
method: "/service/method",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, _, _, err := verifyAccessToken(tt.args.ctx, tt.args.token, tt.args.verifier, tt.args.method)
if tt.wantErr && err == nil {
t.Errorf("got wrong result, should get err: actual: %v ", err)
}
if !tt.wantErr && err != nil {
t.Errorf("got wrong result, should not get err: actual: %v ", err)
}
if tt.wantErr && !errors.IsUnauthenticated(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}