| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package acimport (	"bytes"	"encoding/json"	"flag"	"fmt"	"io/ioutil"	"net/http"	"os"	"strings"	"sync"	"testing"	"devt.de/krotik/common/datautil"	"devt.de/krotik/common/errorutil"	"devt.de/krotik/common/httputil"	"devt.de/krotik/common/httputil/access"	"devt.de/krotik/common/httputil/auth"	"devt.de/krotik/common/stringutil"	"devt.de/krotik/eliasdb/api")const TESTPORT = ":9090"// Main function for all tests in this packagefunc TestMain(m *testing.M) {	var err error	flag.Parse()	hs, wg := startServer()	if hs == nil {		return	}	// Disable access logging	LogAccess = func(v ...interface{}) {}	// Register public endpoints	api.RegisterRestEndpoints(PublicAccessControlEndpointMap)	// Initialise auth handler	AuthHandler = auth.NewCookieAuthHandleFuncWrapper(http.HandleFunc)	// Important statement! - all registered endpoints afterwards	// are subject to access control	api.HandleFunc = AuthHandler.HandleFunc	// Register management endpoints	api.RegisterRestEndpoints(AccessManagementEndpointMap)	// Register dummy page	api.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {		w.Write([]byte("foobar!"))	})	// Initialise user DB	UserDB, err = datautil.NewEnforcedUserDB("test_user.db", "")	errorutil.AssertOk(err)	// Put the UserDB in charge of verifying passwords	AuthHandler.SetAuthFunc(UserDB.CheckUserPassword)	// Initialise ACL's	var conf map[string]interface{}	errorutil.AssertOk(json.Unmarshal(stringutil.StripCStyleComments(DefaultAccessDB), &conf))	at, err := access.NewMemoryACLTableFromConfig(conf)	errorutil.AssertOk(err)	InitACLs(at)	// Connect the ACL object to the AuthHandler - this provides authorization for users	AuthHandler.SetAccessFunc(ACL.CheckHTTPRequest)	// Adding special handlers which redirect to the login page	AuthHandler.CallbackSessionExpired = CallbackSessionExpired	AuthHandler.CallbackUnauthorized = CallbackUnauthorized	// Add users	UserDB.UserDB.AddUserEntry("elias", "elias", nil)	UserDB.UserDB.AddUserEntry("johndoe", "doe", nil)	UserDB.UserDB.AddUserEntry("guest", "g", nil)	// Disable debounce time for unit tests	DebounceTime = 0	// Run the tests	res := m.Run()	// Teardown	stopServer(hs, wg)	// Stop ACL monitoring	ACL.Close()	// Remove files	os.Remove("test_user.db")	os.Exit(res)}func TestSwaggerDefs(t *testing.T) {	// Test we can build swagger defs from the endpoint	data := map[string]interface{}{		"paths":       map[string]interface{}{},		"definitions": map[string]interface{}{},	}	for _, inst := range PublicAccessControlEndpointMap {		inst().SwaggerDefs(data)	}	for _, inst := range AccessManagementEndpointMap {		inst().SwaggerDefs(data)	}}/*Start a HTTP test server.*/func startServer() (*httputil.HTTPServer, *sync.WaitGroup) {	hs := &httputil.HTTPServer{}	var wg sync.WaitGroup	wg.Add(1)	go hs.RunHTTPServer(TESTPORT, &wg)	wg.Wait()	// Server is started	if hs.LastError != nil {		panic(hs.LastError)	}	return hs, &wg}/*Stop a started HTTP test server.*/func stopServer(hs *httputil.HTTPServer, wg *sync.WaitGroup) {	if hs.Running == true {		wg.Add(1)		// Server is shut down		hs.Shutdown()		wg.Wait()	} else {		panic("Server was not running as expected")	}}/*Send a request to a HTTP test server*/func sendTestRequest(contentType string, url string, method string, content []byte,	reqMod func(*http.Request)) string {	body, _ := sendTestRequestResponse(contentType, url, method, content, reqMod)	return body}/*Send a request to a HTTP test server*/func sendTestRequestResponse(contentType string, url string, method string,	content []byte, reqMod func(*http.Request)) (string, *http.Response) {	var req *http.Request	var err error	if content != nil {		req, err = http.NewRequest(method, url, bytes.NewBuffer(content))	} else {		req, err = http.NewRequest(method, url, nil)	}	if err != nil {		panic(err)	}	req.Header.Set("Content-Type", contentType)	if reqMod != nil {		reqMod(req)	}	client := &http.Client{}	resp, err := client.Do(req)	if err != nil {		panic(err)	}	defer resp.Body.Close()	body, _ := ioutil.ReadAll(resp.Body)	bodyStr := strings.Trim(string(body), " \n")	// Try json decoding first	out := bytes.Buffer{}	err = json.Indent(&out, []byte(bodyStr), "", "  ")	if err == nil {		return out.String(), resp	}	// Just return the body	return bodyStr, resp}/*Perform authentication and retrieve an auth cookie*/func doAuth(user, pass string) *http.Cookie {	queryURL := "http://localhost" + TESTPORT	// Send authentication request with correct credentials	res, resp := sendTestRequestResponse("application/json", queryURL+EndpointLogin, "POST", []byte(`{	"user" : "`+user+`",	"pass" : "`+pass+`"}`), nil)	errorutil.AssertTrue(len(resp.Cookies()) > 0, res)	// Right after authentication we only have the authentication cookie - after	// the first visit to a non-public page we will also have a session cookie	authCookie := resp.Cookies()[0]	errorutil.AssertTrue(authCookie.Name == "~aid",		fmt.Sprint("Unexpected name for cookie:", authCookie))	return authCookie}
 |