Manuel Alejandro de Brito Fontes 2b6a56bc40 Update go imports
2021-03-02 06:37:49 -03:00

258 lines
6.5 KiB
Go

// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.
package proxy
import (
"fmt"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"github.com/gitpod-io/gitpod/common-go/log"
"github.com/gitpod-io/gitpod/ws-manager/api"
)
func TestWorkspaceAuthHandler(t *testing.T) {
log.Log.Logger.SetLevel(logrus.PanicLevel)
type testResult struct {
HandlerCalled bool
StatusCode int
}
const (
domain = "test-domain.com"
workspaceID = "workspac-65f4-43c9-bf46-3541b89dca85"
instanceID = "instance-fce1-4ff6-9364-cf6dff0c4ecf"
ownerToken = "owner-token"
testPort = 8080
)
var (
ownerOnlyInfos = map[string]*WorkspaceInfo{
workspaceID: {
WorkspaceID: workspaceID,
InstanceID: instanceID,
Auth: &api.WorkspaceAuthentication{
Admission: api.AdmissionLevel_ADMIT_OWNER_ONLY,
OwnerToken: ownerToken,
},
Ports: []PortInfo{{PortSpec: api.PortSpec{Port: testPort, Visibility: api.PortVisibility_PORT_VISIBILITY_PRIVATE}}},
},
}
publicPortInfos = map[string]*WorkspaceInfo{
workspaceID: {
WorkspaceID: workspaceID,
InstanceID: instanceID,
Auth: &api.WorkspaceAuthentication{
Admission: api.AdmissionLevel_ADMIT_OWNER_ONLY,
OwnerToken: ownerToken,
},
Ports: []PortInfo{{PortSpec: api.PortSpec{Port: testPort, Visibility: api.PortVisibility_PORT_VISIBILITY_PUBLIC}}},
},
}
admitEveryoneInfos = map[string]*WorkspaceInfo{
workspaceID: {
WorkspaceID: workspaceID,
InstanceID: instanceID,
Auth: &api.WorkspaceAuthentication{Admission: api.AdmissionLevel_ADMIT_EVERYONE},
},
}
)
tests := []struct {
Name string
Infos map[string]*WorkspaceInfo
OwnerCookie string
WorkspaceID string
Port string
Expected testResult
}{
{
Name: "workspace not found",
WorkspaceID: workspaceID,
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusNotFound,
},
},
{
Name: "no workspace",
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusForbidden,
},
},
{
Name: "no credentials",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusUnauthorized,
},
},
{
Name: "wrong credentials",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
OwnerCookie: "this is the wrong value",
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusForbidden,
},
},
{
Name: "broken credentials",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
OwnerCookie: "%^? is invalid encoding ",
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusBadRequest,
},
},
{
Name: "correct credentials",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
OwnerCookie: ownerToken,
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "admit everyone without cookie",
Infos: admitEveryoneInfos,
WorkspaceID: workspaceID,
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "admit everyone with cookie",
Infos: admitEveryoneInfos,
WorkspaceID: workspaceID,
OwnerCookie: ownerToken,
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "admit everyone with wrong cookie",
Infos: admitEveryoneInfos,
WorkspaceID: workspaceID,
OwnerCookie: ownerToken + "-this-is-wrong",
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "private port",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
OwnerCookie: ownerToken,
Port: strconv.Itoa(testPort),
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "private port without cookie",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
Port: strconv.Itoa(testPort),
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusUnauthorized,
},
},
{
Name: "private port with wrong cookie",
Infos: ownerOnlyInfos,
WorkspaceID: workspaceID,
OwnerCookie: ownerToken + "-this-is-wrong",
Port: strconv.Itoa(testPort),
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusForbidden,
},
},
{
Name: "public port",
Infos: publicPortInfos,
WorkspaceID: workspaceID,
Port: strconv.Itoa(testPort),
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "broken port",
Infos: publicPortInfos,
WorkspaceID: workspaceID,
Port: "not a valid number",
OwnerCookie: ownerToken,
Expected: testResult{
HandlerCalled: true,
StatusCode: http.StatusOK,
},
},
{
Name: "broken port without cookie",
Infos: publicPortInfos,
WorkspaceID: workspaceID,
Port: "not a valid number",
Expected: testResult{
HandlerCalled: false,
StatusCode: http.StatusUnauthorized,
},
},
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
var res testResult
handler := WorkspaceAuthHandler(domain, &fixedInfoProvider{Infos: test.Infos})(http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
res.HandlerCalled = true
resp.WriteHeader(http.StatusOK)
}))
rr := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/", domain), nil)
if test.OwnerCookie != "" {
setOwnerTokenCookie(req, instanceID, test.OwnerCookie)
}
vars := map[string]string{
workspaceIDIdentifier: test.WorkspaceID,
}
if test.Port != "" {
vars[workspacePortIdentifier] = test.Port
}
req = mux.SetURLVars(req, vars)
handler.ServeHTTP(rr, req)
res.StatusCode = rr.Code
if diff := cmp.Diff(test.Expected, res); diff != "" {
t.Errorf("unexpected response (-want +got):\n%s", diff)
}
})
}
}
func setOwnerTokenCookie(r *http.Request, instanceID, token string) *http.Request {
r.AddCookie(&http.Cookie{Name: "_test_domain_com_ws_" + instanceID + "_owner_", Value: token})
return r
}