Skip to content
Snippets Groups Projects
Commit b2adec62 authored by Christian Pointner's avatar Christian Pointner
Browse files

test-cases for session state subscription

parent 9baed29c
No related branches found
No related tags found
No related merge requests found
......@@ -94,7 +94,7 @@ func newSession() http.Handler {
switch strings.ToLower(request.Backend) {
case "oidc":
if auth.oidc == nil {
sendHTTPErrorResponse(w, http.StatusBadRequest, "OIDC authentication is not enabled")
sendHTTPErrorResponse(w, http.StatusConflict, "OIDC authentication is not enabled")
return
}
s, err := auth.oidc.NewOIDCSession()
......@@ -125,10 +125,11 @@ func getSession() http.Handler {
return
}
ctx := r.Context()
for {
s, sub := auth.sessions.getAndSubscribe(s.ID())
if s == nil {
sendHTTPErrorResponse(w, http.StatusNotFound, "this session does not exist")
sendHTTPErrorResponse(w, http.StatusNotFound, "this session does no longer exist")
return
}
st := s.State()
......@@ -136,7 +137,12 @@ func getSession() http.Handler {
sendHTTPResponse(w, http.StatusOK, s)
return
}
<-sub
select {
case <-sub:
case <-ctx.Done():
sendHTTPErrorResponse(w, http.StatusRequestTimeout, "error while waiting for state change: "+ctx.Err().Error())
return
}
}
})
}
......
......@@ -25,6 +25,8 @@
package auth
import (
"context"
"encoding/json"
"io/ioutil"
"log"
"net/http"
......@@ -32,6 +34,7 @@ import (
"os"
"strings"
"testing"
"time"
"github.com/gorilla/mux"
)
......@@ -148,10 +151,37 @@ func TestAuthNoOIDC(t *testing.T) {
rr = httptest.NewRecorder()
router.ServeHTTP(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("new session should return %d with empty body but returned: %d (%s)", http.StatusBadRequest, rr.Code, http.StatusText(rr.Code))
t.Fatalf("new session request with empty body should return %d but returned: %d (%s)", http.StatusBadRequest, rr.Code, http.StatusText(rr.Code))
}
testVectors := []struct {
body string
code int
}{
{"", http.StatusBadRequest},
{"{}", http.StatusBadRequest},
{"{\"key\":\"value\"}", http.StatusBadRequest},
{"{\"backend\":\"invalid\"}", http.StatusBadRequest},
{"{\"backend\":\"oidc\"}", http.StatusConflict}, // OIDC is disabled!
}
for _, vector := range testVectors {
req, err := http.NewRequest("POST", "/session", strings.NewReader(vector.body))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
rr := httptest.NewRecorder()
router.ServeHTTP(rr, req)
if rr.Code != vector.code {
t.Fatalf("new session request with body '%s' should return %d but returned: %d (%s)", vector.body, vector.code, rr.Code, http.StatusText(rr.Code))
}
}
}
// TODO: implement this - we need a working OIDC IDP for this....
// func TestAuthWidhOIDC(t *testing.T) {
// }
func TestAuthBearerToken(t *testing.T) {
cfg := &Config{}
if err := Init(cfg, nil, nil, nil); err != nil {
......@@ -184,7 +214,7 @@ func TestAuthBearerToken(t *testing.T) {
{"Bearer invalid", http.StatusUnauthorized},
{"Bearer invalid:", http.StatusUnauthorized},
{"Bearer unknown:secret", http.StatusUnauthorized},
{"Bearer " + s.id + ":" + s.secret, http.StatusOK},
{"Bearer " + s.getToken(), http.StatusOK},
}
for _, vector := range testVectors {
......@@ -199,5 +229,76 @@ func TestAuthBearerToken(t *testing.T) {
t.Fatalf("get session should return %d when 'Authorization' header '%s' is found but returned: %d (%s)", vector.code, vector.token, rr.Code, http.StatusText(rr.Code))
}
}
}
func TestAuthWaitForLogin(t *testing.T) {
cfg := &Config{}
if err := Init(cfg, nil, nil, nil); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if auth.sessions == nil {
t.Fatalf("authentication should be enabled but Init created no session manager")
}
s, err := NewSession()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err = auth.sessions.insert(s); err != nil {
t.Fatalf("unexpected error: %v", err)
}
router := mux.NewRouter()
InstallHTTPHandler(router)
timeout := time.AfterFunc(time.Second, func() {
t.Fatalf("waiting for session state change does not respect the request context")
})
req, err := http.NewRequest("GET", "/session?wait-for-login=1", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
req = req.WithContext(ctx)
req.Header.Set("Authorization", "Bearer "+s.getToken())
rr := httptest.NewRecorder()
router.ServeHTTP(rr, req)
if rr.Code != http.StatusRequestTimeout {
t.Fatalf("unexpected reponse code: %d (%s)", rr.Code, http.StatusText(rr.Code))
}
cancel()
timeout.Stop()
for _, state := range []SessionState{SessionStateLoggedIn, SessionStateLoginFailed, SessionStateLoginTimeout} {
s.setState(SessionStateNew)
time.AfterFunc(100*time.Millisecond, func() {
s.setState(state)
})
req, err = http.NewRequest("GET", "/session?wait-for-login=1", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
req = req.WithContext(ctx)
req.Header.Set("Authorization", "Bearer "+s.getToken())
rr = httptest.NewRecorder()
router.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("unexpected reponse code: %d (%s)", rr.Code, http.StatusText(rr.Code))
}
cancel()
result := make(map[string]interface{})
if err = json.NewDecoder(rr.Body).Decode(&result); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if st, ok := result["state"]; !ok {
t.Fatalf("resulting session does not contain the state")
} else if st != state.String() {
t.Fatalf("state of resulting session is wrong, expected: %s, got %v", state.String(), st)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment