arche / internal/archesrv/auth_test.go

commit 154431fd
  1package archesrv
  2
  3import (
  4	"io"
  5	"net/http"
  6	"strings"
  7	"testing"
  8)
  9
 10func TestForgeServer_Login_PageLoads(t *testing.T) {
 11	s, ts := newTestServer(t)
 12	s.db.CreateUser("admin", "pass", true) //nolint:errcheck
 13
 14	resp, err := http.Get(ts.URL + "/login")
 15	if err != nil {
 16		t.Fatalf("GET /login: %v", err)
 17	}
 18	defer resp.Body.Close()
 19	if resp.StatusCode != http.StatusOK {
 20		t.Errorf("want 200, got %d", resp.StatusCode)
 21	}
 22}
 23
 24func TestForgeServer_Login_WrongPassword(t *testing.T) {
 25	s, ts := newTestServer(t)
 26	s.db.CreateUser("admin", "correctpass", true) //nolint:errcheck
 27
 28	jar := newCookieJar()
 29	client := &http.Client{
 30		Jar:           jar,
 31		CheckRedirect: func(_ *http.Request, _ []*http.Request) error { return http.ErrUseLastResponse },
 32	}
 33	resp, err := client.PostForm(ts.URL+"/login", map[string][]string{
 34		"username": {"admin"},
 35		"password": {"wrongpass"},
 36	})
 37	if err != nil {
 38		t.Fatalf("POST /login: %v", err)
 39	}
 40	body, _ := io.ReadAll(resp.Body)
 41	resp.Body.Close()
 42
 43	if resp.StatusCode != http.StatusOK {
 44		t.Errorf("bad creds: want 200 (error page), got %d", resp.StatusCode)
 45	}
 46	if !strings.Contains(string(body), "invalid") {
 47		t.Error("login error page should mention 'invalid'")
 48	}
 49}
 50
 51func TestForgeServer_Logout_InvalidatesSession(t *testing.T) {
 52	s, ts := newTestServer(t)
 53	_, client := loginAsAdmin(t, s, ts)
 54	setupRepoWithDisk(t, s, "myrepo", "private")
 55
 56	r1, err := client.Get(ts.URL + "/myrepo/issues")
 57	if err != nil {
 58		t.Fatalf("GET while logged in: %v", err)
 59	}
 60	r1.Body.Close()
 61	if r1.StatusCode != http.StatusOK {
 62		t.Fatalf("expected 200 while logged in, got %d", r1.StatusCode)
 63	}
 64
 65	r2, err := client.Get(ts.URL + "/logout")
 66	if err != nil {
 67		t.Fatalf("GET /logout: %v", err)
 68	}
 69	r2.Body.Close()
 70
 71	r3, err := client.Get(ts.URL + "/myrepo/issues")
 72	if err != nil {
 73		t.Fatalf("GET after logout: %v", err)
 74	}
 75	r3.Body.Close()
 76	if r3.StatusCode != http.StatusUnauthorized {
 77		t.Errorf("after logout: want 401, got %d", r3.StatusCode)
 78	}
 79}
 80
 81func TestForgeServer_Register_OpenRegistration(t *testing.T) {
 82	s, ts := newTestServerWith(t, func(cfg *Config) { cfg.Auth.Registration = "open" })
 83	s.db.CreateUser("admin", "pass", true) //nolint:errcheck
 84
 85	jar := newCookieJar()
 86	client := &http.Client{Jar: jar, CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
 87		return http.ErrUseLastResponse
 88	}}
 89
 90	resp, err := client.PostForm(ts.URL+"/register", map[string][]string{
 91		"username": {"newuser"},
 92		"password": {"newpass"},
 93		"confirm":  {"newpass"},
 94	})
 95	if err != nil {
 96		t.Fatalf("POST /register: %v", err)
 97	}
 98	resp.Body.Close()
 99	if resp.StatusCode >= 400 {
100		t.Errorf("open registration: want redirect, got %d", resp.StatusCode)
101	}
102
103	u, _, err := s.db.GetUserByName("newuser")
104	if err != nil || u == nil {
105		t.Fatal("new user not found after registration")
106	}
107}
108
109func TestForgeServer_Register_PasswordMismatch(t *testing.T) {
110	s, ts := newTestServerWith(t, func(cfg *Config) { cfg.Auth.Registration = "open" })
111	s.db.CreateUser("admin", "pass", true) //nolint:errcheck
112
113	jar := newCookieJar()
114	client := &http.Client{Jar: jar, CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
115		return http.ErrUseLastResponse
116	}}
117	resp, err := client.PostForm(ts.URL+"/register", map[string][]string{
118		"username": {"alice"},
119		"password": {"abc"},
120		"confirm":  {"xyz"},
121	})
122	if err != nil {
123		t.Fatalf("POST /register: %v", err)
124	}
125	body, _ := io.ReadAll(resp.Body)
126	resp.Body.Close()
127
128	if strings.Contains(string(body), "do not match") == false {
129		u, _, _ := s.db.GetUserByName("alice")
130		if u != nil {
131			t.Error("user should not be created when passwords do not match")
132		}
133	}
134}
135
136func TestForgeServer_Register_InviteRequired(t *testing.T) {
137	s, ts := newTestServerWith(t, func(cfg *Config) { cfg.Auth.Registration = "invite" })
138	admin, _ := s.db.CreateUser("admin", "pass", true)
139
140	jar := newCookieJar()
141	client := &http.Client{Jar: jar, CheckRedirect: func(_ *http.Request, _ []*http.Request) error {
142		return http.ErrUseLastResponse
143	}}
144
145	resp, err := client.PostForm(ts.URL+"/register", map[string][]string{
146		"username": {"bob"},
147		"password": {"pass"},
148		"confirm":  {"pass"},
149	})
150	if err != nil {
151		t.Fatalf("POST /register no invite: %v", err)
152	}
153	body, _ := io.ReadAll(resp.Body)
154	resp.Body.Close()
155
156	u, _, _ := s.db.GetUserByName("bob")
157	if u != nil {
158		t.Error("user should not be created without invite token")
159	}
160	_ = body
161
162	inv, _ := s.db.CreateInvite(admin.ID)
163	resp2, err := client.PostForm(ts.URL+"/register", map[string][]string{
164		"username":     {"carol"},
165		"password":     {"carpass"},
166		"confirm":      {"carpass"},
167		"invite_token": {inv.Token},
168	})
169	if err != nil {
170		t.Fatalf("POST /register with invite: %v", err)
171	}
172	resp2.Body.Close()
173	if resp2.StatusCode >= 400 {
174		t.Errorf("invite registration: want redirect, got %d", resp2.StatusCode)
175	}
176
177	u2, _, err := s.db.GetUserByName("carol")
178	if err != nil || u2 == nil {
179		t.Fatal("user carol not found after invite registration")
180	}
181
182	got, _ := s.db.GetInvite(inv.Token)
183	if got == nil || got.UsedBy == nil {
184		t.Error("invite should be marked as used after registration")
185	}
186}
187
188func TestForgeServer_Register_DisabledByDefault(t *testing.T) {
189	s, ts := newTestServer(t)
190	s.db.CreateUser("admin", "pass", true) //nolint:errcheck
191
192	resp, err := http.Get(ts.URL + "/register")
193	if err != nil {
194		t.Fatalf("GET /register: %v", err)
195	}
196	resp.Body.Close()
197	if resp.StatusCode != http.StatusNotFound {
198		t.Errorf("want 404 (registration disabled), got %d", resp.StatusCode)
199	}
200}