2022-09-11 23:16:40 +02:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2024-07-03 11:33:02 +02:00
|
|
|
"context"
|
2022-09-11 23:16:40 +02:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2023-02-03 21:47:20 +01:00
|
|
|
"github.com/gorilla/mux"
|
2023-02-28 15:01:24 +01:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
2024-03-27 18:48:48 +01:00
|
|
|
"github.com/netbirdio/netbird/management/server"
|
2023-02-03 21:47:20 +01:00
|
|
|
"github.com/netbirdio/netbird/management/server/http/api"
|
2022-09-11 23:16:40 +02:00
|
|
|
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
|
|
|
"github.com/netbirdio/netbird/management/server/mock_server"
|
2024-03-27 18:48:48 +01:00
|
|
|
"github.com/netbirdio/netbird/management/server/status"
|
2022-09-11 23:16:40 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
existingSetupKeyID = "existingSetupKeyID"
|
|
|
|
newSetupKeyName = "New Setup Key"
|
|
|
|
updatedSetupKeyName = "KKKey"
|
|
|
|
notFoundSetupKeyID = "notFoundSetupKeyID"
|
|
|
|
)
|
|
|
|
|
2022-11-05 10:24:50 +01:00
|
|
|
func initSetupKeysTestMetaData(defaultKey *server.SetupKey, newKey *server.SetupKey, updatedSetupKey *server.SetupKey,
|
2023-02-03 21:47:20 +01:00
|
|
|
user *server.User,
|
2023-02-28 15:01:24 +01:00
|
|
|
) *SetupKeysHandler {
|
|
|
|
return &SetupKeysHandler{
|
2022-09-11 23:16:40 +02:00
|
|
|
accountManager: &mock_server.MockAccountManager{
|
2024-09-17 22:15:54 +02:00
|
|
|
GetAccountFromTokenFunc: func(_ context.Context, claims jwtclaims.AuthorizationClaims) (string, string, error) {
|
|
|
|
return testAccountID, user.Id, nil
|
2022-09-11 23:16:40 +02:00
|
|
|
},
|
2024-07-03 11:33:02 +02:00
|
|
|
CreateSetupKeyFunc: func(_ context.Context, _ string, keyName string, typ server.SetupKeyType, _ time.Duration, _ []string,
|
2023-09-06 10:40:45 +02:00
|
|
|
_ int, _ string, ephemeral bool,
|
2023-02-03 21:47:20 +01:00
|
|
|
) (*server.SetupKey, error) {
|
2022-09-11 23:16:40 +02:00
|
|
|
if keyName == newKey.Name || typ != newKey.Type {
|
2023-09-06 10:40:45 +02:00
|
|
|
nk := newKey.Copy()
|
|
|
|
nk.Ephemeral = ephemeral
|
|
|
|
return nk, nil
|
2022-09-11 23:16:40 +02:00
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("failed creating setup key")
|
|
|
|
},
|
2024-07-03 11:33:02 +02:00
|
|
|
GetSetupKeyFunc: func(_ context.Context, accountID, userID, keyID string) (*server.SetupKey, error) {
|
2022-09-11 23:16:40 +02:00
|
|
|
switch keyID {
|
|
|
|
case defaultKey.Id:
|
|
|
|
return defaultKey, nil
|
|
|
|
case newKey.Id:
|
|
|
|
return newKey, nil
|
|
|
|
default:
|
2022-11-11 20:36:45 +01:00
|
|
|
return nil, status.Errorf(status.NotFound, "key %s not found", keyID)
|
2022-09-11 23:16:40 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-07-03 11:33:02 +02:00
|
|
|
SaveSetupKeyFunc: func(_ context.Context, accountID string, key *server.SetupKey, _ string) (*server.SetupKey, error) {
|
2022-09-11 23:16:40 +02:00
|
|
|
if key.Id == updatedSetupKey.Id {
|
|
|
|
return updatedSetupKey, nil
|
|
|
|
}
|
2022-11-11 20:36:45 +01:00
|
|
|
return nil, status.Errorf(status.NotFound, "key %s not found", key.Id)
|
2022-09-11 23:16:40 +02:00
|
|
|
},
|
|
|
|
|
2024-07-03 11:33:02 +02:00
|
|
|
ListSetupKeysFunc: func(_ context.Context, accountID, userID string) ([]*server.SetupKey, error) {
|
2022-09-11 23:16:40 +02:00
|
|
|
return []*server.SetupKey{defaultKey}, nil
|
|
|
|
},
|
|
|
|
},
|
2023-02-03 21:47:20 +01:00
|
|
|
claimsExtractor: jwtclaims.NewClaimsExtractor(
|
|
|
|
jwtclaims.WithFromRequestContext(func(r *http.Request) jwtclaims.AuthorizationClaims {
|
2022-09-11 23:16:40 +02:00
|
|
|
return jwtclaims.AuthorizationClaims{
|
2022-11-05 10:24:50 +01:00
|
|
|
UserId: user.Id,
|
2022-09-11 23:16:40 +02:00
|
|
|
Domain: "hotmail.com",
|
|
|
|
AccountId: testAccountID,
|
|
|
|
}
|
2023-02-03 21:47:20 +01:00
|
|
|
}),
|
|
|
|
),
|
2022-09-11 23:16:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSetupKeysHandlers(t *testing.T) {
|
|
|
|
defaultSetupKey := server.GenerateDefaultSetupKey()
|
|
|
|
defaultSetupKey.Id = existingSetupKeyID
|
|
|
|
|
2022-11-05 10:24:50 +01:00
|
|
|
adminUser := server.NewAdminUser("test_user")
|
|
|
|
|
2022-12-05 13:09:59 +01:00
|
|
|
newSetupKey := server.GenerateSetupKey(newSetupKeyName, server.SetupKeyReusable, 0, []string{"group-1"},
|
2023-09-06 10:40:45 +02:00
|
|
|
server.SetupKeyUnlimitedUsage, true)
|
2022-09-11 23:16:40 +02:00
|
|
|
updatedDefaultSetupKey := defaultSetupKey.Copy()
|
|
|
|
updatedDefaultSetupKey.AutoGroups = []string{"group-1"}
|
|
|
|
updatedDefaultSetupKey.Name = updatedSetupKeyName
|
|
|
|
updatedDefaultSetupKey.Revoked = true
|
|
|
|
|
|
|
|
tt := []struct {
|
|
|
|
name string
|
|
|
|
requestType string
|
|
|
|
requestPath string
|
|
|
|
requestBody io.Reader
|
|
|
|
expectedStatus int
|
|
|
|
expectedBody bool
|
|
|
|
expectedSetupKey *api.SetupKey
|
|
|
|
expectedSetupKeys []*api.SetupKey
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "Get Setup Keys",
|
|
|
|
requestType: http.MethodGet,
|
|
|
|
requestPath: "/api/setup-keys",
|
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
expectedBody: true,
|
|
|
|
expectedSetupKeys: []*api.SetupKey{toResponseBody(defaultSetupKey)},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Get Existing Setup Key",
|
|
|
|
requestType: http.MethodGet,
|
|
|
|
requestPath: "/api/setup-keys/" + existingSetupKeyID,
|
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
expectedBody: true,
|
|
|
|
expectedSetupKey: toResponseBody(defaultSetupKey),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Get Not Existing Setup Key",
|
|
|
|
requestType: http.MethodGet,
|
|
|
|
requestPath: "/api/setup-keys/" + notFoundSetupKeyID,
|
|
|
|
expectedStatus: http.StatusNotFound,
|
|
|
|
expectedBody: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Create Setup Key",
|
|
|
|
requestType: http.MethodPost,
|
|
|
|
requestPath: "/api/setup-keys",
|
|
|
|
requestBody: bytes.NewBuffer(
|
2023-09-06 10:40:45 +02:00
|
|
|
[]byte(fmt.Sprintf("{\"name\":\"%s\",\"type\":\"%s\",\"expires_in\":86400, \"ephemeral\":true}", newSetupKey.Name, newSetupKey.Type))),
|
2022-09-11 23:16:40 +02:00
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
expectedBody: true,
|
|
|
|
expectedSetupKey: toResponseBody(newSetupKey),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "Update Setup Key",
|
|
|
|
requestType: http.MethodPut,
|
|
|
|
requestPath: "/api/setup-keys/" + defaultSetupKey.Id,
|
|
|
|
requestBody: bytes.NewBuffer(
|
|
|
|
[]byte(fmt.Sprintf("{\"name\":\"%s\",\"auto_groups\":[\"%s\"], \"revoked\":%v}",
|
|
|
|
updatedDefaultSetupKey.Type,
|
|
|
|
updatedDefaultSetupKey.AutoGroups[0],
|
|
|
|
updatedDefaultSetupKey.Revoked,
|
|
|
|
))),
|
|
|
|
expectedStatus: http.StatusOK,
|
|
|
|
expectedBody: true,
|
|
|
|
expectedSetupKey: toResponseBody(updatedDefaultSetupKey),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-11-05 10:24:50 +01:00
|
|
|
handler := initSetupKeysTestMetaData(defaultSetupKey, newSetupKey, updatedDefaultSetupKey, adminUser)
|
2022-09-11 23:16:40 +02:00
|
|
|
|
|
|
|
for _, tc := range tt {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
recorder := httptest.NewRecorder()
|
|
|
|
req := httptest.NewRequest(tc.requestType, tc.requestPath, tc.requestBody)
|
|
|
|
|
|
|
|
router := mux.NewRouter()
|
2023-02-28 15:01:24 +01:00
|
|
|
router.HandleFunc("/api/setup-keys", handler.GetAllSetupKeys).Methods("GET", "OPTIONS")
|
|
|
|
router.HandleFunc("/api/setup-keys", handler.CreateSetupKey).Methods("POST", "OPTIONS")
|
2023-05-03 00:15:25 +02:00
|
|
|
router.HandleFunc("/api/setup-keys/{keyId}", handler.GetSetupKey).Methods("GET", "OPTIONS")
|
|
|
|
router.HandleFunc("/api/setup-keys/{keyId}", handler.UpdateSetupKey).Methods("PUT", "OPTIONS")
|
2022-09-11 23:16:40 +02:00
|
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
|
|
|
|
res := recorder.Result()
|
|
|
|
defer res.Body.Close()
|
|
|
|
|
|
|
|
content, err := io.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("I don't know what I expected; %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if status := recorder.Code; status != tc.expectedStatus {
|
|
|
|
t.Errorf("handler returned wrong status code: got %v want %v, content: %s",
|
|
|
|
status, tc.expectedStatus, string(content))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !tc.expectedBody {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if tc.expectedSetupKey != nil {
|
|
|
|
got := &api.SetupKey{}
|
|
|
|
if err = json.Unmarshal(content, &got); err != nil {
|
|
|
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
|
|
|
}
|
|
|
|
assertKeys(t, got, tc.expectedSetupKey)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(tc.expectedSetupKeys) > 0 {
|
|
|
|
var got []*api.SetupKey
|
|
|
|
if err = json.Unmarshal(content, &got); err != nil {
|
|
|
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
|
|
|
}
|
|
|
|
assertKeys(t, got[0], tc.expectedSetupKeys[0])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertKeys(t *testing.T, got *api.SetupKey, expected *api.SetupKey) {
|
2023-11-10 16:33:13 +01:00
|
|
|
t.Helper()
|
2022-09-11 23:16:40 +02:00
|
|
|
// this comparison is done manually because when converting to JSON dates formatted differently
|
|
|
|
// assert.Equal(t, got.UpdatedAt, tc.expectedSetupKey.UpdatedAt) //doesn't work
|
|
|
|
assert.WithinDurationf(t, got.UpdatedAt, expected.UpdatedAt, 0, "")
|
|
|
|
assert.WithinDurationf(t, got.Expires, expected.Expires, 0, "")
|
|
|
|
assert.Equal(t, got.Name, expected.Name)
|
|
|
|
assert.Equal(t, got.Id, expected.Id)
|
|
|
|
assert.Equal(t, got.Key, expected.Key)
|
|
|
|
assert.Equal(t, got.Type, expected.Type)
|
|
|
|
assert.Equal(t, got.UsedTimes, expected.UsedTimes)
|
|
|
|
assert.Equal(t, got.Revoked, expected.Revoked)
|
|
|
|
assert.ElementsMatch(t, got.AutoGroups, expected.AutoGroups)
|
2023-09-06 10:40:45 +02:00
|
|
|
assert.Equal(t, got.Ephemeral, expected.Ephemeral)
|
2022-09-11 23:16:40 +02:00
|
|
|
}
|