git.iko.soy/typeable/oauth2-proxy
on 597ffeb help sign in
281 lines 7.7 kB history raw
1package providers
3import (
4 "context"
5 "errors"
6 "net/http"
7 "net/http/httptest"
8 "net/url"
10 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
11 . "github.com/onsi/ginkgo"
12 . "github.com/onsi/ginkgo/extensions/table"
13 . "github.com/onsi/gomega"
16func testGitLabProvider(hostname string) *GitLabProvider {
17 p := NewGitLabProvider(
18 &ProviderData{
19 ProviderName: "",
20 LoginURL: &url.URL{},
21 RedeemURL: &url.URL{},
22 ProfileURL: &url.URL{},
23 ValidateURL: &url.URL{},
24 Scope: ""})
25 if hostname != "" {
26 updateURL(p.Data().LoginURL, hostname)
27 updateURL(p.Data().RedeemURL, hostname)
28 updateURL(p.Data().ProfileURL, hostname)
29 updateURL(p.Data().ValidateURL, hostname)
30 }
32 return p
35func testGitLabBackend() *httptest.Server {
36 userInfo := `
37 {
38 "nickname": "FooBar",
39 "email": "foo@bar.com",
40 "email_verified": false,
41 "groups": ["foo", "bar"]
42 }
43 `
44 projectInfo := `
45 {
46 "name": "MyProject",
47 "archived": false,
48 "path_with_namespace": "my_group/my_project",
49 "permissions": {
50 "project_access": null,
51 "group_access": {
52 "access_level": 30,
53 "notification_level": 3
54 }
55 }
56 }
57 `
59 personalProjectInfo := `
60 {
61 "name": "MyPersonalProject",
62 "archived": false,
63 "path_with_namespace": "my_profile/my_personal_project",
64 "permissions": {
65 "project_access": {
66 "access_level": 30,
67 "notification_level": 3
68 },
69 "group_access": null
70 }
71 }
72 `
74 archivedProjectInfo := `
75 {
76 "name": "MyArchivedProject",
77 "archived": true,
78 "path_with_namespace": "my_group/my_archived_project",
79 "permissions": {
80 "project_access": {
81 "access_level": 30,
82 "notification_level": 3
83 },
84 "group_access": null
85 }
86 }
87 `
89 authHeader := "Bearer gitlab_access_token"
91 return httptest.NewServer(http.HandlerFunc(
92 func(w http.ResponseWriter, r *http.Request) {
93 switch r.URL.Path {
94 case "/oauth/userinfo":
95 if r.Header["Authorization"][0] == authHeader {
96 w.WriteHeader(200)
97 w.Write([]byte(userInfo))
98 } else {
99 w.WriteHeader(401)
100 }
101 case "/api/v4/projects/my_group/my_project":
102 if r.Header["Authorization"][0] == authHeader {
103 w.WriteHeader(200)
104 w.Write([]byte(projectInfo))
105 } else {
106 w.WriteHeader(401)
107 }
108 case "/api/v4/projects/my_group/my_archived_project":
109 if r.Header["Authorization"][0] == authHeader {
110 w.WriteHeader(200)
111 w.Write([]byte(archivedProjectInfo))
112 } else {
113 w.WriteHeader(401)
114 }
115 case "/api/v4/projects/my_profile/my_personal_project":
116 if r.Header["Authorization"][0] == authHeader {
117 w.WriteHeader(200)
118 w.Write([]byte(personalProjectInfo))
119 } else {
120 w.WriteHeader(401)
121 }
122 case "/api/v4/projects/my_group/my_bad_project":
123 w.WriteHeader(403)
124 default:
125 w.WriteHeader(404)
126 }
127 }))
130var _ = Describe("Gitlab Provider Tests", func() {
131 var p *GitLabProvider
132 var b *httptest.Server
134 BeforeEach(func() {
135 b = testGitLabBackend()
137 bURL, err := url.Parse(b.URL)
138 Expect(err).To(BeNil())
140 p = testGitLabProvider(bURL.Host)
141 })
143 AfterEach(func() {
144 b.Close()
145 })
147 Context("with bad token", func() {
148 It("should trigger an error", func() {
149 p.AllowUnverifiedEmail = false
150 session := &sessions.SessionState{AccessToken: "unexpected_gitlab_access_token"}
151 err := p.EnrichSession(context.Background(), session)
152 Expect(err).To(MatchError(errors.New("failed to retrieve user info: error getting user info: unexpected status \"401\": ")))
153 })
154 })
156 Context("when filtering on email", func() {
157 type emailsTableInput struct {
158 expectedError error
159 expectedValue string
160 allowUnverifiedEmail bool
161 }
163 DescribeTable("should return expected results",
164 func(in emailsTableInput) {
165 p.AllowUnverifiedEmail = in.allowUnverifiedEmail
166 session := &sessions.SessionState{AccessToken: "gitlab_access_token"}
168 err := p.EnrichSession(context.Background(), session)
170 if in.expectedError != nil {
171 Expect(err).To(MatchError(err))
172 } else {
173 Expect(err).To(BeNil())
174 Expect(session.Email).To(Equal(in.expectedValue))
175 }
176 },
177 Entry("unverified email denied", emailsTableInput{
178 expectedError: errors.New("user email is not verified"),
179 allowUnverifiedEmail: false,
180 }),
181 Entry("unverified email allowed", emailsTableInput{
182 expectedError: nil,
183 expectedValue: "foo@bar.com",
184 allowUnverifiedEmail: true,
185 }),
186 )
187 })
189 Context("when filtering on gitlab entities (groups and projects)", func() {
190 type entitiesTableInput struct {
191 expectedValue []string
192 projects []string
193 groups []string
194 }
196 DescribeTable("should return expected results",
197 func(in entitiesTableInput) {
198 p.AllowUnverifiedEmail = true
199 session := &sessions.SessionState{AccessToken: "gitlab_access_token"}
201 err := p.AddProjects(in.projects)
202 Expect(err).To(BeNil())
203 p.SetProjectScope()
205 if len(in.groups) > 0 {
206 p.Groups = in.groups
207 }
209 err = p.EnrichSession(context.Background(), session)
211 Expect(err).To(BeNil())
212 Expect(session.Groups).To(Equal(in.expectedValue))
213 },
214 Entry("project membership valid on group project", entitiesTableInput{
215 expectedValue: []string{"project:my_group/my_project"},
216 projects: []string{"my_group/my_project"},
217 }),
218 Entry("project membership invalid on group project, insufficient access level level", entitiesTableInput{
219 expectedValue: nil,
220 projects: []string{"my_group/my_project=40"},
221 }),
222 Entry("project membership valid on personnal project", entitiesTableInput{
223 expectedValue: []string{"project:my_profile/my_personal_project"},
224 projects: []string{"my_profile/my_personal_project"},
225 }),
226 Entry("project membership invalid on personnal project, insufficient access level", entitiesTableInput{
227 expectedValue: nil,
228 projects: []string{"my_profile/my_personal_project=40"},
229 }),
230 Entry("project membership invalid", entitiesTableInput{
231 expectedValue: nil,
232 projects: []string{"my_group/my_bad_project"},
233 }),
234 Entry("group membership valid", entitiesTableInput{
235 expectedValue: []string{"group:foo"},
236 groups: []string{"foo"},
237 }),
238 Entry("groups and projects", entitiesTableInput{
239 expectedValue: []string{"group:foo", "group:baz", "project:my_group/my_project", "project:my_profile/my_personal_project"},
240 groups: []string{"foo", "baz"},
241 projects: []string{"my_group/my_project", "my_profile/my_personal_project"},
242 }),
243 Entry("archived projects", entitiesTableInput{
244 expectedValue: nil,
245 groups: []string{},
246 projects: []string{"my_group/my_archived_project"},
247 }),
248 )
250 })
252 Context("when generating group list from multiple kind", func() {
253 type entitiesTableInput struct {
254 projects []string
255 groups []string
256 }
258 DescribeTable("should prefix entities with group kind", func(in entitiesTableInput) {
259 p.Groups = in.groups
260 err := p.AddProjects(in.projects)
261 Expect(err).To(BeNil())
263 all := p.PrefixAllowedGroups()
265 Expect(len(all)).To(Equal(len(in.projects) + len(in.groups)))
266 },
267 Entry("simple test case", entitiesTableInput{
268 projects: []string{"my_group/my_project", "my_group/my_other_project"},
269 groups: []string{"mygroup", "myothergroup"},
270 }),
271 Entry("projects only", entitiesTableInput{
272 projects: []string{"my_group/my_project", "my_group/my_other_project"},
273 groups: []string{},
274 }),
275 Entry("groups only", entitiesTableInput{
276 projects: []string{},
277 groups: []string{"mygroup", "myothergroup"},
278 }),
279 )
280 })
281})