244 lines
7.0 KiB
Go
244 lines
7.0 KiB
Go
package httphandlers_test
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fiskerinc/cloud-services/pkg/adminroles"
|
|
"github.com/fiskerinc/cloud-services/pkg/cache"
|
|
"github.com/fiskerinc/cloud-services/pkg/common"
|
|
"github.com/fiskerinc/cloud-services/pkg/common/authproviders"
|
|
c "github.com/fiskerinc/cloud-services/pkg/common/context"
|
|
"github.com/fiskerinc/cloud-services/pkg/db/queries"
|
|
"github.com/fiskerinc/cloud-services/pkg/db/queries/mocks"
|
|
"github.com/fiskerinc/cloud-services/pkg/httphandlers"
|
|
"github.com/fiskerinc/cloud-services/pkg/redis"
|
|
"github.com/fiskerinc/cloud-services/pkg/testhelper"
|
|
)
|
|
|
|
type testCaseAuthAPIToken struct {
|
|
RedisClient redis.Client
|
|
Query queries.APITokensInterface
|
|
APICalls queries.APICallsInterface
|
|
RequiredRoles map[string][]adminroles.RoleID
|
|
JWTAuth bool
|
|
ExpectedProvider string
|
|
testhelper.BasicHttpTest
|
|
}
|
|
|
|
func TestAuthAPIToken(t *testing.T) {
|
|
adminroles.RoleCreate = adminroles.RoleID("efcc3025-e2d8-4212-8227-805c7be39d2c")
|
|
adminroles.RoleDelete = adminroles.RoleID("8f78dce7-f5f9-4033-a10c-c9c7408bfcfe")
|
|
|
|
someErr := errors.New("some err")
|
|
validExpiresAt := time.Now().Add(time.Hour)
|
|
client := &RedisMockAuthAPIToken{
|
|
GetCacheError: redis.ErrNilObject,
|
|
}
|
|
db := &mocks.MockAPITokens{
|
|
DBMockHelper: mocks.DBMockHelper{
|
|
Error: errors.New("token not found"),
|
|
},
|
|
}
|
|
dbCalls := &mocks.MockAPICalls{
|
|
DBMockHelper: mocks.DBMockHelper{Error: nil},
|
|
}
|
|
apiToken := "XXXXXXXXXXXX"
|
|
req := testhelper.MakeTestRequestWithHeaders(http.MethodGet, "/", map[string]string{cache.ApiKeyHeader: apiToken}, nil)
|
|
roles := map[string][]adminroles.RoleID{
|
|
authproviders.Default: {adminroles.RoleCreate},
|
|
}
|
|
|
|
tests := []testCaseAuthAPIToken{
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Good API Token, no required permission",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusOK,
|
|
ExpectedResponse: `OK`,
|
|
},
|
|
RequiredRoles: nil,
|
|
RedisClient: client,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Good API Token",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusOK,
|
|
ExpectedResponse: `OK`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: &mocks.MockAPITokens{
|
|
GetResult: &common.APIToken{
|
|
Token: apiToken,
|
|
Roles: strings.Join([]string{string(adminroles.RoleCreate)}, ","),
|
|
},
|
|
},
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Good API Token with expiration",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusOK,
|
|
ExpectedResponse: `OK`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: &mocks.MockAPITokens{
|
|
GetResult: &common.APIToken{
|
|
Token: apiToken,
|
|
Roles: strings.Join([]string{string(adminroles.RoleCreate)}, ","),
|
|
ExpiresAt: &validExpiresAt,
|
|
},
|
|
},
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Good API Token, without permission",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusUnauthorized,
|
|
ExpectedResponse: `{"message":"missing permission","error":"Unauthorized"}`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: &mocks.MockAPITokens{
|
|
GetResult: &common.APIToken{
|
|
Token: apiToken,
|
|
Roles: strings.Join([]string{string(adminroles.RoleDelete)}, ","),
|
|
},
|
|
},
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Bad API Token",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusUnauthorized,
|
|
ExpectedResponse: `{"message":"token not found","error":"Unauthorized"}`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: db,
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Unknown API Token",
|
|
Request: testhelper.MakeTestRequestWithHeaders(http.MethodGet, "/", map[string]string{cache.ApiKeyHeader: "abc"}, nil),
|
|
ExpectedStatus: http.StatusUnauthorized,
|
|
ExpectedResponse: `{"message":"token not found","error":"Unauthorized"}`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: db,
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "No headers",
|
|
Request: testhelper.MakeTestRequest(http.MethodGet, "/", nil),
|
|
ExpectedStatus: http.StatusUnauthorized,
|
|
ExpectedResponse: `{"message":"no api token header","error":"Unauthorized"}`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: db,
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "No headers, JWT auth",
|
|
Request: testhelper.MakeTestRequest(http.MethodGet, "/", nil),
|
|
ExpectedStatus: http.StatusUnauthorized,
|
|
ExpectedResponse: `{"message":"no authorization header","error":"Unauthorized"}`,
|
|
},
|
|
JWTAuth: true,
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: db,
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "No headers, JWT auth, no required roles",
|
|
Request: testhelper.MakeTestRequest(http.MethodGet, "/", nil),
|
|
ExpectedStatus: http.StatusOK,
|
|
ExpectedResponse: `OK`,
|
|
},
|
|
JWTAuth: true,
|
|
RedisClient: client,
|
|
Query: db,
|
|
APICalls: dbCalls,
|
|
},
|
|
{
|
|
BasicHttpTest: testhelper.BasicHttpTest{
|
|
Name: "Failed api calls log",
|
|
Request: req,
|
|
ExpectedStatus: http.StatusOK,
|
|
ExpectedResponse: `OK`,
|
|
},
|
|
RequiredRoles: roles,
|
|
RedisClient: client,
|
|
Query: &mocks.MockAPITokens{
|
|
GetResult: &common.APIToken{
|
|
Token: apiToken,
|
|
Roles: strings.Join([]string{string(adminroles.RoleCreate)}, ","),
|
|
ExpiresAt: &validExpiresAt,
|
|
},
|
|
},
|
|
APICalls: &mocks.MockAPICalls{
|
|
DBMockHelper: mocks.DBMockHelper{
|
|
Error: someErr,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.Name, func(t *testing.T) {
|
|
handler := setupAuthAPIToken(t, test)
|
|
testhelper.RunBasicHttpTest(t, test.BasicHttpTest, handler)
|
|
})
|
|
}
|
|
}
|
|
|
|
func setupAuthAPIToken(t *testing.T, test testCaseAuthAPIToken) http.HandlerFunc {
|
|
testHandler := func(w http.ResponseWriter, r *http.Request) {
|
|
if test.ExpectedProvider != "" {
|
|
if provider, ok := r.Context().Value(c.ProviderKey).(string); !ok || provider != test.ExpectedProvider {
|
|
t.Errorf(testhelper.TestErrorTemplate, test.Name, test.ExpectedProvider, provider)
|
|
}
|
|
}
|
|
|
|
w.Write([]byte(expectedOkBody))
|
|
}
|
|
|
|
auth := httphandlers.AuthAPIToken{
|
|
APITokens: test.Query,
|
|
APICalls: test.APICalls,
|
|
JWTAuth: test.JWTAuth,
|
|
}
|
|
|
|
return auth.GetHandler(test.RequiredRoles, testHandler)
|
|
}
|
|
|
|
type RedisMockAuthAPIToken struct {
|
|
GetCacheError error
|
|
SetCacheError error
|
|
redis.Connection
|
|
}
|
|
|
|
func (m *RedisMockAuthAPIToken) GetCache(key string, dest interface{}, expire int) error {
|
|
return m.GetCacheError
|
|
}
|
|
|
|
func (m *RedisMockAuthAPIToken) SetCache(string, interface{}, int) error {
|
|
return m.SetCacheError
|
|
}
|