From 44df9cb92abe66cf12e887ef19e60a01461b3558 Mon Sep 17 00:00:00 2001 From: Jeroen Wijenbergh Date: Mon, 25 Apr 2022 16:27:25 +0200 Subject: Tests: Ability to add a custom server and share certificate We also now do not have to skip verification in the test files --- ci/docker/createcert.sh | 14 ++++++++++++++ ci/docker/eduvpn-server.docker | 13 +++---------- ci/docker/go-test.docker | 4 ++++ ci/docker/replaceexpiry.sh | 0 ci/docker/starteduvpn.sh | 0 ci/startcompose.sh | 4 ++++ internal/server.go | 10 +++++++--- state.go | 6 +++++- state_test.go | 42 +++++++++++++++++++----------------------- 9 files changed, 56 insertions(+), 37 deletions(-) create mode 100755 ci/docker/createcert.sh mode change 100644 => 100755 ci/docker/replaceexpiry.sh mode change 100644 => 100755 ci/docker/starteduvpn.sh diff --git a/ci/docker/createcert.sh b/ci/docker/createcert.sh new file mode 100755 index 0000000..22b0ced --- /dev/null +++ b/ci/docker/createcert.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +WEB_FQDN="eduvpnserver" + +# Create self signed cert and key +openssl req \ + -nodes \ + -subj "/CN=${WEB_FQDN}" \ + -x509 \ + -sha256 \ + -newkey rsa:2048 \ + -keyout "./selfsigned/${WEB_FQDN}.key" \ + -out "./selfsigned/${WEB_FQDN}.crt" \ + -days 90 diff --git a/ci/docker/eduvpn-server.docker b/ci/docker/eduvpn-server.docker index ed33691..c570ae3 100644 --- a/ci/docker/eduvpn-server.docker +++ b/ci/docker/eduvpn-server.docker @@ -53,16 +53,9 @@ RUN sed -i "s|fd43::|$(ipcalc -6 -r 64 -n --no-decorate)|" "/etc/vpn-user-portal # Update secrets RUN cp /etc/vpn-user-portal/keys/node.0.key /etc/vpn-server-node/keys/node.key -# Create self signed cert and key -RUN openssl req \ - -nodes \ - -subj "/CN=${WEB_FQDN}" \ - -x509 \ - -sha256 \ - -newkey rsa:2048 \ - -keyout "/etc/pki/tls/private/${WEB_FQDN}.key" \ - -out "/etc/pki/tls/certs/${WEB_FQDN}.crt" \ - -days 90 +# Copy self signed cert and key +COPY ./ci/docker/selfsigned/${WEB_FQDN}.key /etc/pki/tls/private/${WEB_FQDN}.key +COPY ./ci/docker/selfsigned/${WEB_FQDN}.crt /etc/pki/tls/certs/${WEB_FQDN}.crt # Add the start script and expiry script WORKDIR /eduvpn/server diff --git a/ci/docker/go-test.docker b/ci/docker/go-test.docker index 2e6bcd5..04b6a99 100644 --- a/ci/docker/go-test.docker +++ b/ci/docker/go-test.docker @@ -34,5 +34,9 @@ COPY ./internal ./internal # Copy selenium scripts COPY ./selenium_eduvpn.py ./selenium_eduvpn.py +# Update certificates +COPY ./ci/docker/selfsigned/eduvpnserver.crt /usr/local/share/ca-certificates/eduvpnserver.crt +RUN update-ca-certificates + # Run the tests CMD ["go", "test", "-mod=readonly", "./...", "-v"] diff --git a/ci/docker/replaceexpiry.sh b/ci/docker/replaceexpiry.sh old mode 100644 new mode 100755 diff --git a/ci/docker/starteduvpn.sh b/ci/docker/starteduvpn.sh old mode 100644 new mode 100755 diff --git a/ci/startcompose.sh b/ci/startcompose.sh index fa41949..5f0338f 100755 --- a/ci/startcompose.sh +++ b/ci/startcompose.sh @@ -13,5 +13,9 @@ fi # Get absolute path to current directory this script is in SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +# Create self-signed certificate +mkdir -p "$SCRIPT_DIR"/docker/selfsigned +"$SCRIPT_DIR"/docker/createcert.sh + # Get the parent directory to get the root directory docker-compose --file ci/docker/docker-compose.yml --project-directory "$SCRIPT_DIR"/.. up --build --force-recreate --abort-on-container-exit diff --git a/internal/server.go b/internal/server.go index eb7f8fe..c76311e 100644 --- a/internal/server.go +++ b/internal/server.go @@ -53,7 +53,7 @@ func (server *Server) EnsureTokens() error { return nil } -func (servers *Servers) EnsureServer(url string, fsm *FSM, logger *FileLogger) *Server { +func (servers *Servers) EnsureServer(url string, fsm *FSM, logger *FileLogger) (*Server, error) { if servers.List == nil { servers.List = make(map[string]*Server) } @@ -63,10 +63,14 @@ func (servers *Servers) EnsureServer(url string, fsm *FSM, logger *FileLogger) * if !exists || server == nil { server = &Server{} } - server.Init(url, fsm, logger) + serverInitErr := server.Init(url, fsm, logger) + + if serverInitErr != nil { + return nil, serverInitErr + } servers.List[url] = server servers.Current = url - return server + return server, nil } type ServerProfile struct { diff --git a/state.go b/state.go index bafdfb9..6f71cb3 100644 --- a/state.go +++ b/state.go @@ -86,7 +86,11 @@ func (state *VPNState) Connect(url string) (string, error) { return "", errors.New("app not registered") } // New server chosen, ensure the server is fresh - server := state.Servers.EnsureServer(url, &state.FSM, &state.Logger) + server, serverErr := state.Servers.EnsureServer(url, &state.FSM, &state.Logger) + + if serverErr != nil { + return "", serverErr + } // Make sure we are in the chosen state if available state.FSM.GoTransition(internal.CHOSEN_SERVER) // Relogin with oauth diff --git a/state_test.go b/state_test.go index d5d0b11..ce81ba8 100644 --- a/state_test.go +++ b/state_test.go @@ -1,7 +1,6 @@ package eduvpn import ( - "crypto/tls" "errors" "fmt" "net/http" @@ -15,6 +14,14 @@ import ( "github.com/jwijenbergh/eduvpn-common/internal" ) +func getServerURI() string { + serverURI := os.Getenv("SERVER_URI") + if serverURI == "" { + serverURI = "https://eduvpnserver" + } + return serverURI +} + func runCommand(t *testing.T, errBuffer *strings.Builder, name string, args ...string) error { cmd := exec.Command(name, args...) @@ -27,7 +34,7 @@ func runCommand(t *testing.T, errBuffer *strings.Builder, name string, args ...s return cmd.Wait() } -func LoginOAuthSelenium(t *testing.T, url string) { +func loginOAuthSelenium(t *testing.T, url string) { // We could use the go selenium library // But it does not support the latest selenium v4 just yet var errBuffer strings.Builder @@ -37,23 +44,20 @@ func LoginOAuthSelenium(t *testing.T, url string) { } } -func StateCallback(t *testing.T, oldState string, newState string, data string) { +func stateCallback(t *testing.T, oldState string, newState string, data string) { if newState == "OAuth_Started" { - go LoginOAuthSelenium(t, data) + go loginOAuthSelenium(t, data) } } func Test_server(t *testing.T) { state := &VPNState{} - // Do not verify because during testing, the cert is self-signed - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Register("org.eduvpn.app.linux", "configstest", func(old string, new string, data string) { - StateCallback(t, old, new, data) + stateCallback(t, old, new, data) }, false) - _, configErr := state.Connect("https://eduvpnserver") + _, configErr := state.Connect(getServerURI()) if configErr != nil { t.Errorf("Connect error: %v", configErr) @@ -64,9 +68,6 @@ func test_connect_oauth_parameter(t *testing.T, parameters internal.URLParameter state := &VPNState{} configDirectory := "test_oauth_parameters" - // Do not verify because during testing, the cert is self-signed - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Register("org.eduvpn.app.linux", configDirectory, func(oldState string, newState string, data string) { if newState == "OAuth_Started" { baseURL := "http://127.0.0.1:8000/callback" @@ -78,7 +79,7 @@ func test_connect_oauth_parameter(t *testing.T, parameters internal.URLParameter } }, false) - _, configErr := state.Connect("https://eduvpnserver") + _, configErr := state.Connect(getServerURI()) if !errors.As(configErr, expectedErr) { t.Errorf("error %T = %v, wantErr %T", configErr, configErr, expectedErr) @@ -121,14 +122,11 @@ func Test_token_expired(t *testing.T) { // Get a vpn state state := &VPNState{} - // Do not verify because during testing, the cert is self-signed - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Register("org.eduvpn.app.linux", "configsexpired", func(old string, new string, data string) { - StateCallback(t, old, new, data) + stateCallback(t, old, new, data) }, false) - _, configErr := state.Connect("https://eduvpnserver") + _, configErr := state.Connect(getServerURI()) if configErr != nil { t.Errorf("Connect error before expired: %v", configErr) @@ -167,14 +165,11 @@ func Test_token_expired(t *testing.T) { func Test_token_invalid(t *testing.T) { state := &VPNState{} - // Do not verify because during testing, the cert is self-signed - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - state.Register("org.eduvpn.app.linux", "configsinvalid", func(old string, new string, data string) { - StateCallback(t, old, new, data) + stateCallback(t, old, new, data) }, false) - _, configErr := state.Connect("https://eduvpnserver") + _, configErr := state.Connect(getServerURI()) if configErr != nil { t.Errorf("Connect error before invalid: %v", configErr) @@ -190,6 +185,7 @@ func Test_token_invalid(t *testing.T) { server, serverErr := state.Servers.GetCurrentServer() if serverErr != nil { t.Errorf("No server found") + return } // Override tokens with invalid values -- cgit v1.2.3