2023-09-06 22:20:09 +01:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2023-09-15 13:06:31 +01:00
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
2023-09-06 22:20:09 +01:00
|
|
|
"github.com/stretchr/testify/assert"
|
2023-09-15 13:06:31 +01:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
2023-09-06 22:20:09 +01:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
2023-09-15 13:06:31 +01:00
|
|
|
func TestUserAuth_NextFlowUrl(t *testing.T) {
|
|
|
|
u := UserAuth{Data: SessionData{NeedOtp: true}}
|
|
|
|
assert.Equal(t, url.URL{Path: "/login/otp"}, *u.NextFlowUrl(&url.URL{}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/login/otp", RawQuery: url.Values{"redirect": {"/hello"}}.Encode()}, *u.NextFlowUrl(&url.URL{Path: "/hello"}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/login/otp", RawQuery: url.Values{"redirect": {"/hello?a=A"}}.Encode()}, *u.NextFlowUrl(&url.URL{Path: "/hello", RawQuery: url.Values{"a": {"A"}}.Encode()}))
|
|
|
|
u.Data.NeedOtp = false
|
|
|
|
assert.Nil(t, u.NextFlowUrl(&url.URL{}))
|
|
|
|
}
|
|
|
|
|
2023-09-06 22:20:09 +01:00
|
|
|
func TestUserAuth_IsGuest(t *testing.T) {
|
|
|
|
var u UserAuth
|
|
|
|
assert.True(t, u.IsGuest())
|
2023-09-15 13:06:31 +01:00
|
|
|
u.Data.ID = uuid.New()
|
|
|
|
assert.False(t, u.IsGuest())
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakeSessionStore struct {
|
|
|
|
m map[string]any
|
|
|
|
saveFunc func(map[string]any) error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeSessionStore) Context() context.Context { return context.Background() }
|
|
|
|
func (f *fakeSessionStore) SessionID() string { return "fakeSessionStore" }
|
|
|
|
func (f *fakeSessionStore) Set(key string, value interface{}) { f.m[key] = value }
|
|
|
|
|
|
|
|
func (f *fakeSessionStore) Get(key string) (a interface{}, ok bool) {
|
|
|
|
if a, ok = f.m[key]; false {
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeSessionStore) Delete(key string) (i interface{}) {
|
|
|
|
i = f.m[key]
|
|
|
|
delete(f.m, key)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeSessionStore) Save() error {
|
|
|
|
return f.saveFunc(f.m)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fakeSessionStore) Flush() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUserAuth_SaveSessionData(t *testing.T) {
|
|
|
|
f := &fakeSessionStore{m: make(map[string]any)}
|
|
|
|
u := UserAuth{Data: SessionData{ID: uuid.UUID{5, 6, 7}, NeedOtp: true}, Session: f}
|
|
|
|
|
|
|
|
// fail to save
|
|
|
|
f.saveFunc = func(m map[string]any) error { return fmt.Errorf("failed") }
|
|
|
|
assert.Error(t, u.SaveSessionData())
|
|
|
|
|
|
|
|
// try with success
|
|
|
|
var m2 map[string]any
|
|
|
|
f.saveFunc = func(m map[string]any) error {
|
|
|
|
m2 = m
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
assert.NoError(t, u.SaveSessionData())
|
|
|
|
assert.Equal(t, map[string]any{"session-data": SessionData{ID: uuid.UUID{5, 6, 7}, NeedOtp: true}}, m2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRequireAuthentication(t *testing.T) {
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOptionalAuthentication(t *testing.T) {
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "https://example.com/hello", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
auth, err := internalAuthenticationHandler(rec, req)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, auth.IsGuest())
|
|
|
|
auth.Data.ID = uuid.UUID{5, 6, 7}
|
|
|
|
assert.NoError(t, auth.SaveSessionData())
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_internalAuthenticationHandler(t *testing.T) {
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "https://example.com/hello", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
auth, err := internalAuthenticationHandler(rec, req)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.True(t, auth.IsGuest())
|
|
|
|
auth.Data.ID = uuid.UUID{5, 6, 7}
|
|
|
|
assert.NoError(t, auth.SaveSessionData())
|
|
|
|
|
|
|
|
req, err = http.NewRequest(http.MethodGet, "https://example.com/world", nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
req.Header.Set("Cookie", rec.Header().Get("Set-Cookie"))
|
|
|
|
rec = httptest.NewRecorder()
|
|
|
|
auth, err = internalAuthenticationHandler(rec, req)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, auth.IsGuest())
|
|
|
|
assert.Equal(t, uuid.UUID{5, 6, 7}, auth.Data.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPrepareRedirectUrl(t *testing.T) {
|
|
|
|
assert.Equal(t, url.URL{Path: "/hello"}, *PrepareRedirectUrl("/hello", &url.URL{}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/world"}, *PrepareRedirectUrl("/world", &url.URL{}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"redirect": {"/hello"}}.Encode()}, *PrepareRedirectUrl("/a", &url.URL{Path: "/hello"}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"redirect": {"/hello?a=A"}}.Encode()}, *PrepareRedirectUrl("/a", &url.URL{Path: "/hello", RawQuery: url.Values{"a": {"A"}}.Encode()}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"redirect": {"/hello?a=A&b=B"}}.Encode()}, *PrepareRedirectUrl("/a", &url.URL{Path: "/hello", RawQuery: url.Values{"a": {"A"}, "b": {"B"}}.Encode()}))
|
2023-09-24 18:24:16 +01:00
|
|
|
|
|
|
|
assert.Equal(t, url.URL{Path: "/hello", RawQuery: "z=y"}, *PrepareRedirectUrl("/hello?z=y", &url.URL{}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/world", RawQuery: "z=y"}, *PrepareRedirectUrl("/world?z=y", &url.URL{}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"z": {"y"}, "redirect": {"/hello"}}.Encode()}, *PrepareRedirectUrl("/a?z=y", &url.URL{Path: "/hello"}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"z": {"y"}, "redirect": {"/hello?a=A"}}.Encode()}, *PrepareRedirectUrl("/a?z=y", &url.URL{Path: "/hello", RawQuery: url.Values{"a": {"A"}}.Encode()}))
|
|
|
|
assert.Equal(t, url.URL{Path: "/a", RawQuery: url.Values{"z": {"y"}, "redirect": {"/hello?a=A&b=B"}}.Encode()}, *PrepareRedirectUrl("/a?z=y", &url.URL{Path: "/hello", RawQuery: url.Values{"a": {"A"}, "b": {"B"}}.Encode()}))
|
2023-09-06 22:20:09 +01:00
|
|
|
}
|