Skip to content
Snippets Groups Projects
Commit 41c0ae87 authored by Neil-Jocelyn Schark's avatar Neil-Jocelyn Schark
Browse files

add multiple tokens without changing featureset

parent 8dc25ded
No related branches found
No related tags found
1 merge request!977Resolve "Improve token usage for users"
Pipeline #218670 failed
This commit is part of merge request !977. Comments created here will be created in the context of that merge request.
...@@ -76,14 +76,15 @@ func createTestUsers() error { ...@@ -76,14 +76,15 @@ func createTestUsers() error {
testUserPWD := createHashedAndSaltedPassword("user", salt) testUserPWD := createHashedAndSaltedPassword("user", salt)
testRandPWD := createHashedAndSaltedPassword("aurelius", salt) testRandPWD := createHashedAndSaltedPassword("aurelius", salt)
wrongTokens := []string{"wrong token"}
users := []rbacImpl.User{ users := []rbacImpl.User{
{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD}, {UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD},
{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD}, {UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD},
{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Token: "wrong token"}, {UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Tokens: wrongTokens},
} }
for _, u := range users { for _, u := range users {
err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0})) err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, wrongTokens, salt, conflict.Metadata{ResourceVersion: 0}))
if err != nil { if err != nil {
return err return err
} }
...@@ -146,7 +147,7 @@ func createTestUserToken(userName string, validTokenRequired bool) (string, erro ...@@ -146,7 +147,7 @@ func createTestUserToken(userName string, validTokenRequired bool) (string, erro
if err != nil { if err != nil {
return token, err return token, err
} }
user.SetToken(token) user.AddToken(token)
err = userService.Update(user) err = userService.Update(user)
if err != nil { if err != nil {
......
...@@ -430,7 +430,7 @@ func ensureDefaultUserExists() error { ...@@ -430,7 +430,7 @@ func ensureDefaultUserExists() error {
hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(usedPassword), []byte(salt), 1, 64*1024, 4, 32)) hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(usedPassword), []byte(salt), 1, 64*1024, 4, 32))
err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), "", salt, conflict.Metadata{ResourceVersion: 0})) err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), []string{}, salt, conflict.Metadata{ResourceVersion: 0}))
if err != nil { if err != nil {
return err return err
} }
......
...@@ -12,8 +12,10 @@ type User interface { ...@@ -12,8 +12,10 @@ type User interface {
Name() string Name() string
GetRoles() map[string]string GetRoles() map[string]string
GetPassword() string GetPassword() string
GetToken() string GetTokens() []string
SetToken(string) SetTokens([]string)
AddToken(string)
RemoveToken(string) error
GetSalt() string GetSalt() string
GetMetadata() conflict.Metadata GetMetadata() conflict.Metadata
} }
...@@ -24,7 +26,7 @@ type LoadedUser struct { ...@@ -24,7 +26,7 @@ type LoadedUser struct {
UserName string `json:"username"` UserName string `json:"username"`
Roles map[string]string `json:"roles,omitempty"` Roles map[string]string `json:"roles,omitempty"`
Password string `json:"password"` Password string `json:"password"`
Token string `json:"token,omitempty"` Tokens []string `json:"tokens,omitempty"`
Salt string `json:"salt" bson:"salt"` Salt string `json:"salt" bson:"salt"`
Metadata conflict.Metadata `json:"metadata" bson:"metadata"` Metadata conflict.Metadata `json:"metadata" bson:"metadata"`
} }
...@@ -92,7 +92,7 @@ func (s AuthServer) Login(ctx context.Context, request *apb.LoginRequest) (*apb. ...@@ -92,7 +92,7 @@ func (s AuthServer) Login(ctx context.Context, request *apb.LoginRequest) (*apb.
return nil, err return nil, err
} }
userToUpdate.SetToken(token) userToUpdate.AddToken(token)
err = s.userService.Update(userToUpdate) err = s.userService.Update(userToUpdate)
if err != nil { if err != nil {
...@@ -155,7 +155,7 @@ func (s AuthServer) isCorrectPassword(storedPassword, salt, loginPassword string ...@@ -155,7 +155,7 @@ func (s AuthServer) isCorrectPassword(storedPassword, salt, loginPassword string
} }
// handleLogout checks if the provided user name matches with the one associated with token and // handleLogout checks if the provided user name matches with the one associated with token and
// replaces the stored token of the user with an empty string. // removed the token from all tokens of the user
func (s AuthServer) handleLogout(ctx context.Context, userName string) error { func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
md, ok := metadata.FromIncomingContext(ctx) md, ok := metadata.FromIncomingContext(ctx)
if !ok { if !ok {
...@@ -179,7 +179,17 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error { ...@@ -179,7 +179,17 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
return err return err
} }
if token != storedUser.GetToken() { storedTokens := storedUser.GetTokens()
foundToken := false
for _, storedToken := range storedTokens {
if storedToken == token {
storedUser.RemoveToken(token)
foundToken = true
break
}
}
if !foundToken {
return status.Errorf(codes.Aborted, "missing match of token provied for user") return status.Errorf(codes.Aborted, "missing match of token provied for user")
} }
...@@ -187,7 +197,7 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error { ...@@ -187,7 +197,7 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
UserName: storedUser.Name(), UserName: storedUser.Name(),
Roles: storedUser.GetRoles(), Roles: storedUser.GetRoles(),
Password: storedUser.GetPassword(), Password: storedUser.GetPassword(),
Token: " ", Tokens: storedUser.GetTokens(),
Salt: storedUser.GetSalt(), Salt: storedUser.GetSalt(),
Metadata: storedUser.GetMetadata(), Metadata: storedUser.GetMetadata(),
}) })
......
...@@ -97,7 +97,17 @@ func (auth *AuthInterceptor) authorize(ctx context.Context, method string) error ...@@ -97,7 +97,17 @@ func (auth *AuthInterceptor) authorize(ctx context.Context, method string) error
return err return err
} }
if user.GetToken() != token { storedTokens := user.GetTokens()
foundToken := false
for _, storedToken := range storedTokens {
if storedToken == token {
foundToken = true
break
}
}
if !foundToken {
return status.Errorf(codes.PermissionDenied, "invalid token") return status.Errorf(codes.PermissionDenied, "invalid token")
} }
......
...@@ -98,14 +98,15 @@ func createTestUsers(userService rbacInterfaces.UserService) error { ...@@ -98,14 +98,15 @@ func createTestUsers(userService rbacInterfaces.UserService) error {
testUserPWD := createHashedAndSaltedPassword("user", salt) testUserPWD := createHashedAndSaltedPassword("user", salt)
testRandPWD := createHashedAndSaltedPassword("aurelius", salt) testRandPWD := createHashedAndSaltedPassword("aurelius", salt)
wrongTokens := []string{"Wrong token"}
users := []rbac.User{ users := []rbac.User{
{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD}, {UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD},
{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD}, {UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD},
{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Token: "wrong token"}, {UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Tokens: wrongTokens},
} }
wrongTokens = []string{}
for _, u := range users { for _, u := range users {
err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0})) err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, wrongTokens, salt, conflict.Metadata{ResourceVersion: 0}))
if err != nil { if err != nil {
return err return err
} }
...@@ -176,6 +177,7 @@ func patchLogger(t *testing.T) { ...@@ -176,6 +177,7 @@ func patchLogger(t *testing.T) {
// be attached to the provided user. Else the user won't have the token and can not be authorized. // be attached to the provided user. Else the user won't have the token and can not be authorized.
func createTestUserToken(userName string, validTokenRequired bool, userService rbacInterfaces.UserService, jwt *rbac.JWTManager) (string, error) { func createTestUserToken(userName string, validTokenRequired bool, userService rbacInterfaces.UserService, jwt *rbac.JWTManager) (string, error) {
token, err := jwt.GenerateToken(rbac.User{UserName: userName}) token, err := jwt.GenerateToken(rbac.User{UserName: userName})
tokens := []string{token}
if err != nil { if err != nil {
return token, err return token, err
} }
...@@ -185,7 +187,7 @@ func createTestUserToken(userName string, validTokenRequired bool, userService r ...@@ -185,7 +187,7 @@ func createTestUserToken(userName string, validTokenRequired bool, userService r
if err != nil { if err != nil {
return token, err return token, err
} }
user.SetToken(token) user.SetTokens(tokens)
err = userService.Update(user) err = userService.Update(user)
if err != nil { if err != nil {
......
...@@ -97,7 +97,7 @@ func (u UserServer) CreateUsers(ctx context.Context, request *apb.CreateUsersReq ...@@ -97,7 +97,7 @@ func (u UserServer) CreateUsers(ctx context.Context, request *apb.CreateUsersReq
userID = uuid.New() userID = uuid.New()
} }
user := rbac.NewUser(userID, user.Name, roles, string(hashedPassword), user.Token, salt, conflict.Metadata{ResourceVersion: 0}) user := rbac.NewUser(userID, user.Name, roles, string(hashedPassword), []string{}, salt, conflict.Metadata{ResourceVersion: 0})
err = u.userService.Add(user) err = u.userService.Add(user)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
...@@ -204,7 +204,7 @@ func (u UserServer) UpdateUsers(ctx context.Context, request *apb.UpdateUsersReq ...@@ -204,7 +204,7 @@ func (u UserServer) UpdateUsers(ctx context.Context, request *apb.UpdateUsersReq
hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(user.Password), []byte(storedUser.GetSalt()), 1, 64*1024, 4, 32)) hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(user.Password), []byte(storedUser.GetSalt()), 1, 64*1024, 4, 32))
userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), user.Token, storedUser.GetSalt(), conflict.Metadata{ userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), []string{}, storedUser.GetSalt(), conflict.Metadata{
ResourceVersion: int(user.Metadata.ResourceVersion)}) ResourceVersion: int(user.Metadata.ResourceVersion)})
usr, _ := userToUpdate.(*rbac.User) usr, _ := userToUpdate.(*rbac.User)
......
...@@ -138,7 +138,7 @@ func (s *UserService) createUserFromStore(loadedUser rbac.LoadedUser) rbac.User ...@@ -138,7 +138,7 @@ func (s *UserService) createUserFromStore(loadedUser rbac.LoadedUser) rbac.User
loadedUser.UserName, loadedUser.UserName,
loadedUser.Roles, loadedUser.Roles,
loadedUser.Password, loadedUser.Password,
loadedUser.Token, loadedUser.Tokens,
loadedUser.Salt, loadedUser.Salt,
loadedUser.Metadata, loadedUser.Metadata,
) )
......
...@@ -2,6 +2,7 @@ package rbac ...@@ -2,6 +2,7 @@ package rbac
import ( import (
"encoding/json" "encoding/json"
"errors"
"code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/conflict"
"code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
...@@ -16,7 +17,7 @@ type User struct { ...@@ -16,7 +17,7 @@ type User struct {
UserName string `json:"username"` UserName string `json:"username"`
Roles map[string]string `json:"roles,omitempty"` Roles map[string]string `json:"roles,omitempty"`
Password string `json:"password"` Password string `json:"password"`
Token string `json:"token,omitempty"` Tokens []string `json:"token,omitempty"`
Salt string `json:"salt"` Salt string `json:"salt"`
} }
...@@ -25,7 +26,7 @@ func NewUser(id uuid.UUID, ...@@ -25,7 +26,7 @@ func NewUser(id uuid.UUID,
name string, name string,
roles map[string]string, roles map[string]string,
pw string, pw string,
token string, tokens []string,
salt string, salt string,
metadata conflict.Metadata, metadata conflict.Metadata,
) rbac.User { ) rbac.User {
...@@ -34,7 +35,7 @@ func NewUser(id uuid.UUID, ...@@ -34,7 +35,7 @@ func NewUser(id uuid.UUID,
UserName: name, UserName: name,
Roles: roles, Roles: roles,
Password: pw, Password: pw,
Token: token, Tokens: tokens,
Salt: salt, Salt: salt,
Metadata: metadata, Metadata: metadata,
} }
...@@ -66,8 +67,8 @@ func (u *User) GetRoles() map[string]string { ...@@ -66,8 +67,8 @@ func (u *User) GetRoles() map[string]string {
} }
// GetToken returns the token of the user. // GetToken returns the token of the user.
func (u *User) GetToken() string { func (u *User) GetTokens() []string {
return u.Token return u.Tokens
} }
// SetName sets the name of the user. // SetName sets the name of the user.
...@@ -76,8 +77,25 @@ func (u *User) SetName(name string) { ...@@ -76,8 +77,25 @@ func (u *User) SetName(name string) {
} }
// SetToken sets the token of the user. // SetToken sets the token of the user.
func (u *User) SetToken(token string) { func (u *User) SetTokens(tokens []string) {
u.Token = token u.Tokens = tokens
}
// AddToken adds a token to the user.
func (u *User) AddToken(token string) {
u.Tokens = append(u.Tokens, token)
}
// RemoveToken removes a token from the user.
func (u *User) RemoveToken(inputToken string) error {
for i, token := range u.Tokens {
if token == inputToken {
u.Tokens = append(u.Tokens[:i], u.Tokens[i+1:]...)
return nil
}
}
err := errors.New("token not found")
return err
} }
// GetSalt returns the salt of the user. // GetSalt returns the salt of the user.
...@@ -92,7 +110,7 @@ func (u *User) MarshalJSON() ([]byte, error) { ...@@ -92,7 +110,7 @@ func (u *User) MarshalJSON() ([]byte, error) {
UserName string `json:"username"` UserName string `json:"username"`
Roles map[string]string `json:"roles,omitempty"` Roles map[string]string `json:"roles,omitempty"`
Password string `json:"password"` Password string `json:"password"`
Token string `json:"token,omitempty"` Tokens []string `json:"tokens,omitempty"`
Salt string `json:"salt"` Salt string `json:"salt"`
Metadata conflict.Metadata `json:"metadata"` Metadata conflict.Metadata `json:"metadata"`
}{ }{
...@@ -100,7 +118,7 @@ func (u *User) MarshalJSON() ([]byte, error) { ...@@ -100,7 +118,7 @@ func (u *User) MarshalJSON() ([]byte, error) {
UserName: u.Name(), UserName: u.Name(),
Roles: u.Roles, Roles: u.Roles,
Password: u.Password, Password: u.Password,
Token: u.Token, Tokens: u.Tokens,
Salt: u.Salt, Salt: u.Salt,
Metadata: u.Metadata, Metadata: u.Metadata,
}) })
...@@ -113,7 +131,7 @@ func (u *User) MarshalBSON() ([]byte, error) { ...@@ -113,7 +131,7 @@ func (u *User) MarshalBSON() ([]byte, error) {
UserName string `bson:"username"` UserName string `bson:"username"`
Roles map[string]string `bson:"roles,omitempty"` Roles map[string]string `bson:"roles,omitempty"`
Password string `bson:"password"` Password string `bson:"password"`
Token string `bson:"token,omitempty"` Tokens []string `bson:"tokens,omitempty"`
Salt string `bson:"salt"` Salt string `bson:"salt"`
Metadata conflict.Metadata `bson:"metadata"` Metadata conflict.Metadata `bson:"metadata"`
}{ }{
...@@ -121,7 +139,7 @@ func (u *User) MarshalBSON() ([]byte, error) { ...@@ -121,7 +139,7 @@ func (u *User) MarshalBSON() ([]byte, error) {
UserName: u.Name(), UserName: u.Name(),
Roles: u.Roles, Roles: u.Roles,
Password: u.Password, Password: u.Password,
Token: u.Token, Tokens: u.Tokens,
Salt: u.Salt, Salt: u.Salt,
Metadata: u.Metadata, Metadata: u.Metadata,
}) })
......
...@@ -20,7 +20,8 @@ func TestFileSystemUserStore_Add(t *testing.T) { ...@@ -20,7 +20,8 @@ func TestFileSystemUserStore_Add(t *testing.T) {
} }
var idtest uuid.UUID var idtest uuid.UUID
var role map[string]string var role map[string]string
testingUser := NewUser(idtest, "testUser", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tokens := []string{"svsvsfbdwbwbev"}
testingUser := NewUser(idtest, "testUser", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
tests := []struct { tests := []struct {
name string name string
args args args args
...@@ -51,7 +52,8 @@ func TestFileSystemUserStore_Delete(t *testing.T) { ...@@ -51,7 +52,8 @@ func TestFileSystemUserStore_Delete(t *testing.T) {
} }
var idtest uuid.UUID var idtest uuid.UUID
var role map[string]string var role map[string]string
testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tokens := []string{"svsvsfbdwbwbev"}
testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
tests := []struct { tests := []struct {
name string name string
args args args args
...@@ -84,7 +86,8 @@ func TestFileSystemUserStore_Get(t *testing.T) { ...@@ -84,7 +86,8 @@ func TestFileSystemUserStore_Get(t *testing.T) {
} }
var idtest uuid.UUID var idtest uuid.UUID
var role map[string]string var role map[string]string
testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tokens := []string{"svsvsfbdwbwbev"}
testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
tests := []struct { tests := []struct {
name string name string
args args args args
...@@ -96,7 +99,7 @@ func TestFileSystemUserStore_Get(t *testing.T) { ...@@ -96,7 +99,7 @@ func TestFileSystemUserStore_Get(t *testing.T) {
args{ args{
store.Query{ID: idtest, Name: "test"}, store.Query{ID: idtest, Name: "test"},
}, },
rbac.LoadedUser{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Token: "svsvsfbdwbwbev", Salt: "svswvasfbw"}, rbac.LoadedUser{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Tokens: tokens, Salt: "svswvasfbw"},
false, false,
}, },
} }
...@@ -123,9 +126,10 @@ func TestFileSystemUserStore_GetAll(t *testing.T) { ...@@ -123,9 +126,10 @@ func TestFileSystemUserStore_GetAll(t *testing.T) {
var idtest uuid.UUID var idtest uuid.UUID
var role map[string]string var role map[string]string
testingUser1 := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbevasf", "svswvasfbwasv", conflict.Metadata{}) tokens := []string{"svsvsfbdwbwbev"}
testingUser2 := NewUser(idtest, "", role, "abc", "svsvsfbdwbwbevsav", "svswvasfbwadf", conflict.Metadata{}) testingUser1 := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbwasv", conflict.Metadata{})
testingUser3 := NewUser(idtest, "", role, "lmn", "svsvsfbdwbwbevscv", "svswvasfbwasd", conflict.Metadata{}) testingUser2 := NewUser(idtest, "", role, "abc", tokens, "svswvasfbwadf", conflict.Metadata{})
testingUser3 := NewUser(idtest, "", role, "lmn", tokens, "svswvasfbwasd", conflict.Metadata{})
tests := []struct { tests := []struct {
name string name string
want []rbac.LoadedUser want []rbac.LoadedUser
...@@ -133,7 +137,7 @@ func TestFileSystemUserStore_GetAll(t *testing.T) { ...@@ -133,7 +137,7 @@ func TestFileSystemUserStore_GetAll(t *testing.T) {
}{ }{
{ {
"testUser", "testUser",
[]rbac.LoadedUser{{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Token: "svsvsfbdwbwbevasf", Salt: "svswvasfbwasv"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "abc", Token: "svsvsfbdwbwbevsav", Salt: "svswvasfbwadf"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "lmn", Token: "svsvsfbdwbwbevscv", Salt: "svswvasfbwasd"}}, []rbac.LoadedUser{{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Tokens: tokens, Salt: "svswvasfbwasv"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "abc", Tokens: tokens, Salt: "svswvasfbwadf"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "lmn", Tokens: tokens, Salt: "svswvasfbwasd"}},
false, false,
}, },
} }
...@@ -175,7 +179,8 @@ func TestFileSystemUserStore_Update(t *testing.T) { ...@@ -175,7 +179,8 @@ func TestFileSystemUserStore_Update(t *testing.T) {
} }
var idtest uuid.UUID var idtest uuid.UUID
var role map[string]string var role map[string]string
testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tokens := []string{"svsvsfbdwbwbev"}
testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
tests := []struct { tests := []struct {
name string name string
args args args args
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment