Skip to content
Snippets Groups Projects
auth_test.go 8.21 KiB
Newer Older
  • Learn to ignore specific revisions
  • package server
    
    import (
    	"context"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"log"
    
    	"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
    
    	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/config"
    	"code.fbi.h-da.de/danet/gosdn/controller/conflict"
    
    	eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
    
    	"github.com/bufbuild/protovalidate-go"
    
    	"github.com/google/uuid"
    	"github.com/stretchr/testify/assert"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"google.golang.org/grpc/metadata"
    
    func getTestAuthServer(t *testing.T) *AuthServer {
    
    	jwtManager := rbac.NewJWTManager("test", time.Minute)
    
    	eventService := eventservice.NewMockEventService()
    
    
    	userStore := rbac.NewMemoryUserStore()
    
    	userService := rbac.NewUserService(userStore, eventService)
    
    
    	roleStore := rbac.NewMemoryRoleStore()
    
    	roleService := rbac.NewRoleService(roleStore, eventService)
    
    	protoValidator, err := protovalidate.New()
    	if err != nil {
    		panic(err)
    	}
    
    	s := NewAuthServer(jwtManager, userService, protoValidator)
    	err = clearAndCreateAuthTestSetup(s.userService, roleService)
    
    	if err != nil {
    		t.Fatalf("%v", err)
    	}
    
    	return s
    }
    
    
    func TestAuth_Login(t *testing.T) {
    
    	type args struct {
    		ctx     context.Context
    		request *apb.LoginRequest
    	}
    	tests := []struct {
    
    		name             string
    		args             args
    		want             string
    		wantErr          bool
    		validationErrors []*validate.Violation
    
    			name: "default login",
    			want: "testAdmin",
    			args: args{
    				request: &apb.LoginRequest{
    					Username: "testAdmin",
    					Pwd:      "admin",
    				},
    			},
    			wantErr: false,
    		},
    		{
    			name: "login fail wrong pwd",
    
    				request: &apb.LoginRequest{
    					Username: "testAdmin",
    					Pwd:      "nope",
    				},
    
    		{
    			name: "login fail due to missing username",
    			want: "",
    			args: args{
    				request: &apb.LoginRequest{
    					Username: "",
    					Pwd:      "nope",
    				},
    			},
    			wantErr: true,
    			validationErrors: []*validate.Violation{
    				{
    
    					FieldPath:    stringToPointer("username"),
    					ConstraintId: stringToPointer("required"),
    					Message:      stringToPointer("value is required"),
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			resp, err := r.Login(tt.args.ctx, tt.args.request)
    			if (err != nil) != tt.wantErr {
    
    				t.Errorf("Auth.Login() error = %v, wantErr %v", err, tt.wantErr)
    
    			if tt.wantErr {
    				assertValidationErrors(t, err, tt.validationErrors)
    			}
    
    
    			if resp != nil {
    				got := resp.Token
    				if got == "" {
    					t.Errorf("Auth.Login() = %v, want non empty token", got)
    				}
    
    func TestAuth_Logout(t *testing.T) {
    
    	s := getTestAuthServer(t)
    	validToken, err := createTestUserToken("testAdmin", true, s.userService, s.jwtManager)
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	if err != nil {
    		log.Fatal(err)
    	}
    
    
    	type args struct {
    		ctx     context.Context
    		request *apb.LogoutRequest
    	}
    	tests := []struct {
    
    		name             string
    		args             args
    		want             *apb.LogoutResponse
    		wantErr          bool
    		validationErrors []*validate.Violation
    
    			name: "default log out",
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    				ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
    
    				request: &apb.LogoutRequest{
    					Username: "testAdmin",
    
    			want:    &apb.LogoutResponse{},
    
    		{
    			name: "default log out fails due to missing username",
    			args: args{
    				ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
    				request: &apb.LogoutRequest{
    					Username: "",
    				},
    			},
    			want:    &apb.LogoutResponse{},
    			wantErr: true,
    			validationErrors: []*validate.Violation{
    				{
    
    					FieldPath:    stringToPointer("username"),
    					ConstraintId: stringToPointer("required"),
    					Message:      stringToPointer("value is required"),
    
    	}
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    			_, err := s.Logout(tt.args.ctx, tt.args.request)
    
    			if (err != nil) != tt.wantErr {
    
    				t.Errorf("Auth.Logout() error = %v, wantErr %v", err, tt.wantErr)
    
    
    			if tt.wantErr {
    				assertValidationErrors(t, err, tt.validationErrors)
    			}
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    
    func TestAuth_isValidUser(t *testing.T) {
    	type args struct {
    		user rbac.User
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default valid user",
    			args: args{
    				user: rbac.User{
    					UserName: "testAdmin",
    					Password: "admin",
    				},
    			},
    			wantErr: false,
    		},
    		{
    			name: "error wrong user name",
    			args: args{
    				user: rbac.User{
    					UserName: "foo",
    					Password: "admin",
    				},
    			},
    			wantErr: true,
    		},
    		{
    			name: "error wrong password",
    			args: args{
    				user: rbac.User{
    					UserName: "testAdmin",
    					Password: "foo",
    				},
    			},
    			wantErr: true,
    		},
    	}
    
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    			if err := s.isValidUser(tt.args.user); (err != nil) != tt.wantErr {
    				t.Errorf("Auth.isValidUser() error = %v, wantErr %v", err, tt.wantErr)
    			}
    		})
    	}
    }
    
    func TestAuth_handleLogout(t *testing.T) {
    
    	s := getTestAuthServer(t)
    	validToken, err := createTestUserToken("testAdmin", true, s.userService, s.jwtManager)
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	if err != nil {
    		log.Fatal(err)
    	}
    
    
    	invalidToken, err := createTestUserToken("testAdmin", false, s.userService, s.jwtManager)
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	type args struct {
    		ctx      context.Context
    		userName string
    	}
    	tests := []struct {
    		name    string
    		args    args
    		wantErr bool
    	}{
    		{
    			name: "default handle logout",
    			args: args{
    				ctx:      metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
    				userName: "testAdmin",
    			},
    			wantErr: false,
    		},
    		{
    			name: "fail no metadata",
    			args: args{
    				ctx:      context.TODO(),
    				userName: "testAdmin",
    			},
    			wantErr: true,
    		},
    		{
    			name: "fail invalid token for user",
    			args: args{
    				ctx:      metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", invalidToken)),
    				userName: "testAdmin",
    			},
    			wantErr: true,
    		},
    		{
    			name: "fail invalid user for token",
    			args: args{
    				ctx:      metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
    				userName: "testUser",
    			},
    			wantErr: true,
    		},
    	}
    	for _, tt := range tests {
    		t.Run(tt.name, func(t *testing.T) {
    			if err := s.handleLogout(tt.args.ctx, tt.args.userName); (err != nil) != tt.wantErr {
    				t.Errorf("Auth.handleLogout() error = %v, wantErr %v", err, tt.wantErr)
    			}
    		})
    	}
    }
    
    
    func TestAuth_addTokenAndEnsureTokenLimit_addKey(t *testing.T) {
    	config.MaxTokensPerUser = 2
    	userID := uuid.New()
    	user := rbac.NewUser(userID, "testUser", map[string]string{}, "password", []string{"token1"}, "salt", conflict.Metadata{ResourceVersion: 0})
    	err := addTokenAndEnsureTokenLimit(user, "token2")
    	assert.Nil(t, err)
    
    	assert.Equal(t, 2, len(user.GetTokens()))
    	assert.Equal(t, "token1", user.GetTokens()[0])
    	assert.Equal(t, "token2", user.GetTokens()[1])
    }
    
    func TestAuth_addTokenAndEnsureTokenLimit_removeOldKey(t *testing.T) {
    	config.MaxTokensPerUser = 2
    	userID := uuid.New()
    	user := rbac.NewUser(userID, "testUser", map[string]string{}, "password", []string{"token1", "token2"}, "salt", conflict.Metadata{ResourceVersion: 0})
    	err := addTokenAndEnsureTokenLimit(user, "token3")
    	assert.Nil(t, err)
    
    	assert.Equal(t, 2, len(user.GetTokens()))
    	assert.Equal(t, "token2", user.GetTokens()[0])
    	assert.Equal(t, "token3", user.GetTokens()[1])
    }
    func Test_removeTokenFromUserIfExists(t *testing.T) {
    	config.MaxTokensPerUser = 100
    	user := rbac.NewUser(uuid.New(), "testUser", map[string]string{}, "password", []string{"token1", "token2", "token3"}, "salt", conflict.Metadata{ResourceVersion: 0})
    
    	err := removeTokenFromUserIfExists(user, "token2")
    	assert.Nil(t, err)
    	assert.Equal(t, []string{"token1", "token3"}, user.GetTokens())
    
    	err = removeTokenFromUserIfExists(user, "token4")
    	assert.NotNil(t, err)
    	assert.Equal(t, []string{"token1", "token3"}, user.GetTokens())
    
    	user = rbac.NewUser(uuid.New(), "testUser", map[string]string{}, "password", []string{}, "salt", conflict.Metadata{ResourceVersion: 0})
    	err = removeTokenFromUserIfExists(user, "token4")
    	assert.NotNil(t, err)
    }