loginsrv

Unnamed repository; edit this file 'description' to name the repository.
git clone git@jamesshield.xyz:repos/loginsrv.git
Log | Files | Refs | README | LICENSE

commit 0444d0b57159b9dddc4e57e1ac4e9f49bf07eba2
parent 21e85dc4f939428303b61ad3b4983288481be57a
Author: Sebastian Mancke <s.mancke@tarent.de>
Date:   Sun,  7 May 2017 16:22:03 +0200

added more tests for oauth flow

Diffstat:
Mlogin/handler.go | 12+++++++++++-
Mlogin/handler_test.go | 122++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Moauth2/manager.go | 4++++
3 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/login/handler.go b/login/handler.go @@ -20,7 +20,7 @@ const contentTypePlain = "text/plain" type Handler struct { backends []Backend - oauth *oauth2.Manager + oauth oauthManager config *Config } @@ -295,3 +295,13 @@ func (h *Handler) authenticate(username, password string) (bool, model.UserInfo, } return false, model.UserInfo{}, nil } + +type oauthManager interface { + Handle(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) + AddConfig(providerName string, opts map[string]string) error + GetConfigFromRequest(r *http.Request) (oauth2.Config, error) +} diff --git a/login/handler_test.go b/login/handler_test.go @@ -23,11 +23,26 @@ func TestHandler_NewFromConfig(t *testing.T) { testCases := []struct { config *Config backendCount int + oauthCount int expectError bool }{ { + &Config{ + Backends: Options{ + "simple": map[string]string{"bob": "secret"}, + }, + Oauth: Options{ + "github": map[string]string{"client_id": "xxx", "client_secret": "YYY"}, + }, + }, + 1, + 1, + false, + }, + { &Config{Backends: Options{"simple": map[string]string{"bob": "secret"}}}, 1, + 0, false, }, // error cases @@ -35,16 +50,29 @@ func TestHandler_NewFromConfig(t *testing.T) { // init error because no users are provided &Config{Backends: Options{"simple": map[string]string{}}}, 1, + 0, + true, + }, + { + &Config{ + Oauth: Options{ + "FOOO": map[string]string{"client_id": "xxx", "client_secret": "YYY"}, + }, + }, + 0, + 0, true, }, { &Config{}, 0, + 0, true, }, { &Config{Backends: Options{"simpleFoo": map[string]string{"bob": "secret"}}}, 1, + 0, true, }, } @@ -55,7 +83,8 @@ func TestHandler_NewFromConfig(t *testing.T) { assert.Error(t, err) } else { assert.NoError(t, err) - assert.Equal(t, 1, len(h.backends)) + assert.Equal(t, test.backendCount, len(h.backends)) + assert.Equal(t, test.oauthCount, len(h.oauth.(*oauth2.Manager).GetConfigs())) } }) } @@ -100,6 +129,73 @@ func TestHandler_LoginJson(t *testing.T) { assert.Equal(t, "Wrong credentials", recorder.Body.String()) } +func TestHandler_HandleOauth(t *testing.T) { + managerMock := &oauth2ManagerMock{ + _GetConfigFromRequest: func(r *http.Request) (oauth2.Config, error) { + return oauth2.Config{}, nil + }, + } + handler := &Handler{ + oauth: managerMock, + config: DefaultConfig(), + } + + // test start flow redirect + managerMock._Handle = func(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) { + w.Header().Set("Location", "http://example.com") + w.WriteHeader(303) + return true, false, model.UserInfo{}, nil + } + recorder := httptest.NewRecorder() + handler.ServeHTTP(recorder, req("GET", "/login/github", "")) + assert.Equal(t, 303, recorder.Code) + assert.Equal(t, "http://example.com", recorder.Header().Get("Location")) + + // test authentication + managerMock._Handle = func(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) { + return false, true, model.UserInfo{Sub: "marvin"}, nil + } + recorder = httptest.NewRecorder() + handler.ServeHTTP(recorder, req("GET", "/login/github", "")) + assert.Equal(t, 200, recorder.Code) + token, err := tokenAsMap(recorder.Body.String()) + assert.NoError(t, err) + assert.Equal(t, "marvin", token["sub"]) + + // test error in oauth + managerMock._Handle = func(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) { + return false, false, model.UserInfo{}, errors.New("some error") + } + recorder = httptest.NewRecorder() + handler.ServeHTTP(recorder, req("GET", "/login/github", "")) + assert.Equal(t, 500, recorder.Code) + + // test failure if no oauth action would be taken, because the url parameters where + // missing an action parts + managerMock._Handle = func(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) { + return false, false, model.UserInfo{}, nil + } + recorder = httptest.NewRecorder() + handler.ServeHTTP(recorder, req("GET", "/login/github", "")) + assert.Equal(t, 403, recorder.Code) +} + func TestHandler_LoginWeb(t *testing.T) { // redirectSuccess recorder := call(req("POST", "/context/login", "username=bob&password=secret", TypeForm, AcceptHtml)) @@ -273,3 +369,27 @@ type errorTestBackend string func (h errorTestBackend) Authenticate(username, password string) (bool, model.UserInfo, error) { return false, model.UserInfo{}, errors.New(string(h)) } + +type oauth2ManagerMock struct { + _Handle func(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) + _AddConfig func(providerName string, opts map[string]string) error + _GetConfigFromRequest func(r *http.Request) (oauth2.Config, error) +} + +func (m *oauth2ManagerMock) Handle(w http.ResponseWriter, r *http.Request) ( + startedFlow bool, + authenticated bool, + userInfo model.UserInfo, + err error) { + return m._Handle(w, r) +} +func (m *oauth2ManagerMock) AddConfig(providerName string, opts map[string]string) error { + return m._AddConfig(providerName, opts) +} +func (m *oauth2ManagerMock) GetConfigFromRequest(r *http.Request) (oauth2.Config, error) { + return m._GetConfigFromRequest(r) +} diff --git a/oauth2/manager.go b/oauth2/manager.go @@ -122,6 +122,10 @@ func (manager *Manager) AddConfig(providerName string, opts map[string]string) e return nil } +func (manager *Manager) GetConfigs() map[string]Config { + return manager.configs +} + func redirectUriFromRequest(r *http.Request) string { u := url.URL{} u.Path = r.URL.Path