package rootmux import ( "encoding/json" "net/http" "net/http/cookiejar" "net/http/httptest" "net/url" "os" "testing" "time" "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 mailSubject = models.MailSubject{Year: 2021, Month: 1, Subject: "[Ecolyo] Newsletter"} mailSubjectStr string monthlyInfo = models.MonthlyInfo{Year: 2021, Month: 1, Info: "Informations du mois", Image: "imagebase64"} monthlyInfoStr string monthlyNews = models.MonthlyNews{Year: 2021, Month: 1, Title: "", Content: "Nouvelles fonctionnalités"} monthlyNewsStr string newPoll = models.Poll{Year: 2021, Month: 1, Question: "pollQuestion", Link: "pollLink"} newPollStr string partnersInfo = models.PartnersInfo{ID: 1, GRDFFailure: false, EnedisFailure: false, EGLFailure: true, NotificationActivated: true} partnersInfoStr string consent = models.Consent{Firstname: "Foo", Lastname: "Bar", PointID: 123456} consentStr 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") os.Setenv("MEILI_MASTER_KEY", "masterkey") os.Setenv("MEILI_HOST", "http://localhost:7700") os.Setenv("SGE_API_TOKEN", "sgeApiToken") // Setup the token manager to use debug mode os.Setenv("DEBUG_MODE", "true") tokens.Init("../configs/tokenskey.json", true) // Convert example objects to string mailSubjectBytes, _ := json.Marshal(mailSubject) mailSubjectStr = string(mailSubjectBytes) 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) consentBytes, _ := json.Marshal(consent) consentStr = string(consentBytes) 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) // SGE API tests sgeTests(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 pass empty) do("GET", "/api/common/monthlyReport?year=2021&month=12", noH, "", http.StatusOK, `{"year":2021,"month":12,"subject":"[Ecolyo] Votre bilan de décembre 2021","info":"","image":"","newsTitle":"","newsContent":"","question":"","link":""}`) // 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/1", xsrfHeader, "", http.StatusNotFound, "") // Try to create a monthlyNews (must pass) do("PUT", "/api/admin/monthlyNews", xsrfHeader, monthlyNewsStr, http.StatusCreated, `{"year":2021,"month":1,"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":1,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) // Try to get the monthlyNews created (must pass) do("GET", "/api/admin/monthlyNews/2021/1", xsrfHeader, "", http.StatusOK, `{"year":2021,"month":1,"title":"Les nouveautés du service","content":"Nouvelles fonctionnalités"`) // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Votre bilan de janvier 2021","info":"","image":"","newsTitle":"Les nouveautés du service","newsContent":"Nouvelles fonctionnalités","question":"","link":""}`) // 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/1", 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/1", xsrfHeader, "", http.StatusOK, newPollStr) // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Votre bilan de janvier 2021","info":"","image":"","newsTitle":"Les nouveautés du service","newsContent":"Nouvelles fonctionnalités","question":"pollQuestion","link":"pollLink"}`) // 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/1", 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/1", xsrfHeader, "", http.StatusOK, monthlyInfoStr) // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Votre bilan de janvier 2021","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 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/1", 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/1", xsrfHeader, "", http.StatusNotFound, "") // Try to create a mail subject (must pass) do("PUT", "/api/admin/mailSubject", xsrfHeader, mailSubjectStr, http.StatusCreated, mailSubjectStr) // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Newsletter","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/1", 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/1", xsrfHeader, "", http.StatusNotFound, "") // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Newsletter","info":"Informations du mois","image":"imagebase64","newsTitle":"","newsContent":"","question":"","link":""`) // Try to delete the mail subject created (must pass) do("DELETE", "/api/admin/mailSubject/2021/1", xsrfHeader, "", http.StatusOK, "successful delete") // Try to get a mail subject after it is deleted (must fail because not found) do("GET", "/api/admin/mailSubject/2021/1", xsrfHeader, "", http.StatusNotFound, "") // Try to get the monthlyReport (must pass) do("GET", "/api/common/monthlyReport/2021/1", noH, "", http.StatusOK, `{"year":2021,"month":1,"subject":"[Ecolyo] Votre bilan de janvier 2021","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 sgeTests(t *testing.T) { // Create the tester ts, do, _ := createTester(t) defer ts.Close() // Close the tester // Try to create a consent (must fail) do("POST", "/api/sge/consent", noH, consentStr, http.StatusUnauthorized, "invalid token") // Try to get a consent (must fail) do("GET", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token") // Try to update a consent (must fail) do("PUT", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token") // Try to delete a consent (must fail) do("DELETE", "/api/sge/consent/1", noH, "", http.StatusUnauthorized, "invalid token") // Create correct authorization header sgeApiHeader := map[string]string{"Authorization": "Bearer " + auth.SGEApiToken} // Try to create a consent (must pass) do("POST", "/api/sge/consent", sgeApiHeader, consentStr, http.StatusCreated, `{"ID":1`) // Wait for new documents to be indexed time.Sleep(1 * time.Second) // Try to update a consent (must pass) do("PUT", "/api/sge/consent/1", sgeApiHeader, `{"serviceId":123456}`, http.StatusOK, `{"ID":1`) // Try to get a consent that doesn't exist (must fail not found) do("GET", "/api/sge/consent/123456", sgeApiHeader, "", http.StatusNotFound, `consent not found`) // Try to get a consent (must pass) do("GET", "/api/sge/consent/1", sgeApiHeader, "", http.StatusOK, `{"ID":1`) // Try to login (must pass) do("GET", "/OAuth2Login", noH, "", http.StatusOK, "") 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 get first 50 consents (must pass) do("GET", "/api/admin/consent?limit=50&page=0", xsrfHeader, "", http.StatusOK, `{"totalRows":1,"rows":[{"ID":1`) // Try to search for a consent (must pass) do("GET", "/api/admin/consent?search=123456", xsrfHeader, "", http.StatusOK, `[{"ID":1`) // Try to delete a consent (must pass) do("DELETE", "/api/sge/consent/1", sgeApiHeader, "", http.StatusOK, "") } 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) }