package rootmux import ( "encoding/json" "net/http" "net/http/cookiejar" "net/http/httptest" "net/url" "os" "testing" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/auth" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/mocks" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/models" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/tester" "forge.grandlyon.com/web-et-numerique/llle_project/backoffice-server/internal/tokens" ) var ( oAuth2Server *httptest.Server monthlyInfo = models.MonthlyInfo{Year: 2021, Month: 0, Info: "Informations du mois", Image: "imagebase64"} monthlyInfoStr string monthlyNews = models.MonthlyNews{Year: 2021, Month: 0, Title: "", Content: "Nouvelles fonctionnalités"} monthlyNewsStr string newPoll = models.Poll{Year: 2021, Month: 0, Question: "pollQuestion", Link: "pollLink"} newPollStr string partnersInfo = models.PartnersInfo{ID: 1, GRDFFailure: false, EnedisFailure: false, EGLFailure: true, NotificationActivated: true} partnersInfoStr string noH map[string]string ) func TestMain(m *testing.M) { // Create the OAuth2 mock server oAuth2Server = httptest.NewServer(mocks.CreateMockOAuth2()) defer oAuth2Server.Close() // Set the constants with environment variables os.Setenv("HOSTNAME", "localhost") os.Setenv("ADMIN_ROLE", "ADMINS") os.Setenv("CLIENT_ID", "foo") os.Setenv("CLIENT_SECRET", "bar") os.Setenv("TOKEN_URL", oAuth2Server.URL+"/token") os.Setenv("USERINFO_URL", oAuth2Server.URL+"/userinfo") os.Setenv("LOGOUT_URL", oAuth2Server.URL+"/logout") // Setup the token manager to use debug mode os.Setenv("DEBUG_MODE", "true") tokens.Init("../configs/tokenskey.json", true) // Convert example objects to string monthlyNewsBytes, _ := json.Marshal(monthlyNews) monthlyNewsStr = string(monthlyNewsBytes) monthlyInfoBytes, _ := json.Marshal(monthlyInfo) monthlyInfoStr = string(monthlyInfoBytes) partnersInfoBytes, _ := json.Marshal(partnersInfo) partnersInfoStr = string(partnersInfoBytes) newPollBytes, _ := json.Marshal(newPoll) newPollStr = string(newPollBytes) code := m.Run() // Remove the database os.Remove("backoffice.db") os.Exit(code) } func TestAll(t *testing.T) { // Set up testers os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth-wrong-state") // Set the server to access failing OAuth2 endpoints oauth2Tests(t) os.Setenv("AUTH_URL", oAuth2Server.URL+"/auth") // Set the server to access the correct OAuth2Endpoint unloggedTests(t) os.Setenv("USERINFO_URL", oAuth2Server.URL+"/admininfo") adminTests(t) } /** SECURITY TESTS (this tests are to check that the security protections works) **/ func oauth2Tests(t *testing.T) { // Create the tester ts, do, _ := createTester(t) defer ts.Close() // Close the tester // Try to login (must fail) do("GET", "/OAuth2Login", noH, "", http.StatusInternalServerError, "invalid oauth state") } /** UNLOGGED USER TESTS (this tests are to check that the security protections works) **/ func unloggedTests(t *testing.T) { // Create the tester ts, do, _ := createTester(t) defer ts.Close() // Close the tester // Try to create a monthlyNews (must fail) do("PUT", "/api/admin/monthlyNews", noH, monthlyNewsStr, http.StatusUnauthorized, "error extracting token") // Try to get a monthlyReport (must fail because no parameters are given) do("GET", "/api/common/monthlyReport", noH, "", http.StatusBadRequest, "") // Try to get a monthlyReport (must fail because not found) do("GET", "/api/common/monthlyReport?year=2021&month=12", noH, "", http.StatusNotFound, "") // Try to get partnersInfo (must pass) do("GET", "/api/common/partnersInfo", noH, "", http.StatusOK, `{"ID":1,"grdf_failure":false,"enedis_failure":false,"egl_failure":false,"notification_activated":false}`) } /** ADMIN TESTS (this tests are to check that an administrator can edit a newsletter's content) **/ func adminTests(t *testing.T) { // Create the tester ts, do, _ := createTester(t) defer ts.Close() // Close the tester tests := func() { // Get the XSRF Token response := do("GET", "/api/common/WhoAmI", noH, "", http.StatusOK, "") token := auth.TokenData{} json.Unmarshal([]byte(response), &token) xsrfHeader := map[string]string{"XSRF-TOKEN": token.XSRFToken} // Try to create a monthlyNews without the XSRF-TOKEN (must fail) do("PUT", "/api/admin/monthlyNews", noH, monthlyNewsStr, http.StatusUnauthorized, "XSRF protection triggered") // Try to create a monthlyNews without body (must fail) do("PUT", "/api/admin/monthlyNews", xsrfHeader, "", http.StatusBadRequest, "request body is empty") // Try to get a monthlyNews before it is created (must fail because not found) do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to create a monthlyNews (must pass) do("PUT", "/api/admin/monthlyNews", xsrfHeader, monthlyNewsStr, http.StatusCreated, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) // Try to update a monthlyNews (must pass) do("PUT", "/api/admin/monthlyNews", xsrfHeader, monthlyNewsStr, http.StatusOK, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) // Try to get the monthlyNews created (must pass) do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusOK, `{"year":2021,"month":0,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) // Try to get the monthlyReport (must fail because monthlyInfo not found) do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusNotFound, "") // Try to create a poll without the XSRF-TOKEN (must fail) do("PUT", "/api/admin/poll", noH, newPollStr, http.StatusUnauthorized, "XSRF protection triggered") // Try to create a poll without body (must fail) do("PUT", "/api/admin/poll", xsrfHeader, "", http.StatusBadRequest, "request body is empty") // Try to get a poll before it is created (must fail because not found') do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to create a poll (must pass) do("PUT", "/api/admin/poll", xsrfHeader, newPollStr, http.StatusCreated, newPollStr) // Try to update a poll (must pass) do("PUT", "/api/admin/poll", xsrfHeader, newPollStr, http.StatusOK, newPollStr) // Try to get the poll created (must pass) do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusOK, newPollStr) // Try to get the monthlyReport (must fail because monthlyInfo not found) do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusNotFound, "") // Try to create a monthlyInfo without the XSRF-TOKEN (must fail) do("PUT", "/api/admin/monthlyInfo", noH, monthlyInfoStr, http.StatusUnauthorized, "XSRF protection triggered") // Try to create a monthlyInfo without body (must fail) do("PUT", "/api/admin/monthlyInfo", xsrfHeader, "", http.StatusBadRequest, "request body is empty") // Try to get a monthlyInfo before it is created (must fail because not found) do("GET", "/api/admin/monthlyInfo/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to create a monthlyInfo (must pass) do("PUT", "/api/admin/monthlyInfo", xsrfHeader, monthlyInfoStr, http.StatusCreated, monthlyInfoStr) // Try to update a monthlyInfo (must pass) do("PUT", "/api/admin/monthlyInfo", xsrfHeader, monthlyInfoStr, http.StatusOK, monthlyInfoStr) // Try to get the monthlyInfo created (must pass) do("GET", "/api/admin/monthlyInfo/2021/0", xsrfHeader, "", http.StatusOK, monthlyInfoStr) // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","image":"imagebase64","newsTitle":"Les nouveautés du service","newsContent":"Nouvelles fonctionnalités","question":"pollQuestion","link":"pollLink"`) // Try to update the partnersInfo (must pass) do("PUT", "/api/admin/partnersInfo", xsrfHeader, partnersInfoStr, http.StatusOK, partnersInfoStr) // Try to get the monthlyInfo created (must pass) do("GET", "/api/common/partnersInfo", xsrfHeader, "", http.StatusOK, partnersInfoStr) // Try to delete the monthlyNews created (must pass) do("DELETE", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusOK, "successful delete") // Try to get a monthlyNews after it is deleted (must fail because not found) do("GET", "/api/admin/monthlyNews/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","image":"imagebase64","newsTitle":"","newsContent":"","question":"pollQuestion","link":"pollLink"`) // Try to delete the poll created (must pass) do("DELETE", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusOK, "successful delete") // Try to get a poll after it is deleted (must fail because not found) do("GET", "/api/admin/poll/2021/0", xsrfHeader, "", http.StatusNotFound, "") // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/0", noH, "", http.StatusOK, `{"year":2021,"month":0,"info":"Informations du mois","image":"imagebase64","newsTitle":"","newsContent":"","question":"","link":""`) } // Try to login (must pass) do("GET", "/OAuth2Login", noH, "", http.StatusOK, "") // Run the tests tests() // Try to logout (must pass) do("GET", "/Logout", noH, "", http.StatusOK, "") // Try to get a monthlyNews again (must fail) do("GET", "/api/admin/monthlyNews", noH, "", http.StatusUnauthorized, "error extracting token") // Try to get a poll again (must fail) do("GET", "/api/admin/poll", noH, "", http.StatusUnauthorized, "error extracting token") } func createTester(t *testing.T) (*httptest.Server, tester.DoFn, tester.DoFn) { // Create the server mux := CreateRootMux() ts := httptest.NewServer(mux.Router) url, _ := url.Parse(ts.URL) port := url.Port() mux.Manager.Config.RedirectURL = "http://" + os.Getenv("HOSTNAME") + ":" + port + "/OAuth2Callback" mux.Manager.Hostname = "http://" + os.Getenv("HOSTNAME") + ":" + port // Create the cookie jar jar, _ := cookiejar.New(nil) // wrap the testing function return ts, tester.CreateServerTester(t, port, os.Getenv("HOSTNAME"), jar), tester.CreateServerTester(t, port, os.Getenv("HOSTNAME"), nil) }