1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
13 "git.arvados.org/arvados.git/lib/ctrlctx"
14 "git.arvados.org/arvados.git/sdk/go/arvados"
15 "git.arvados.org/arvados.git/sdk/go/arvadostest"
16 "git.arvados.org/arvados.git/sdk/go/auth"
17 check "gopkg.in/check.v1"
20 var _ = check.Suite(&LogoutSuite{})
21 var emptyURL = &url.URL{}
23 type LogoutStub struct {
25 redirectLocation *url.URL
28 func (as *LogoutStub) CheckCalls(c *check.C, returnURL *url.URL) bool {
29 actual := as.APIStub.Calls(as.APIStub.Logout)
30 allOK := c.Check(actual, check.Not(check.HasLen), 0,
31 check.Commentf("Logout stub never called"))
32 expected := returnURL.String()
33 for _, call := range actual {
34 opts, ok := call.Options.(arvados.LogoutOptions)
35 allOK = c.Check(ok, check.Equals, true,
36 check.Commentf("call options were not LogoutOptions")) &&
37 c.Check(opts.ReturnTo, check.Equals, expected) &&
43 func (as *LogoutStub) Logout(ctx context.Context, options arvados.LogoutOptions) (arvados.LogoutResponse, error) {
44 as.APIStub.Logout(ctx, options)
45 loc := as.redirectLocation.String()
47 loc = options.ReturnTo
49 return arvados.LogoutResponse{
50 RedirectLocation: loc,
54 type LogoutSuite struct {
58 func (s *LogoutSuite) badReturnURL(path string) *url.URL {
66 func (s *LogoutSuite) goodReturnURL(path string) *url.URL {
67 u, _ := url.Parse(s.cluster.Services.Workbench2.ExternalURL.String())
72 func (s *LogoutSuite) setupFederation(loginCluster string) {
73 if loginCluster == "" {
74 s.cluster.Login.Test.Enable = true
76 s.cluster.Login.LoginCluster = loginCluster
78 dbconn := ctrlctx.DBConnector{PostgreSQL: s.cluster.PostgreSQL}
79 s.fed = New(s.ctx, s.cluster, nil, dbconn.GetDB)
82 func (s *LogoutSuite) setupStub(c *check.C, id string, stubURL *url.URL, stubErr error) *LogoutStub {
83 loc, err := url.Parse(stubURL.String())
84 c.Check(err, check.IsNil)
85 stub := LogoutStub{redirectLocation: loc}
87 if id == s.cluster.ClusterID {
90 s.addDirectRemote(c, id, &stub)
95 func (s *LogoutSuite) v2Token(clusterID string) string {
96 return fmt.Sprintf("v2/%s-gj3su-12345abcde67890/abcdefghijklmnopqrstuvwxy", clusterID)
99 func (s *LogoutSuite) TestLocalLogoutOK(c *check.C) {
100 s.setupFederation("")
101 resp, err := s.fed.Logout(s.ctx, arvados.LogoutOptions{})
102 c.Check(err, check.IsNil)
103 c.Check(resp.RedirectLocation, check.Equals, s.cluster.Services.Workbench2.ExternalURL.String())
106 func (s *LogoutSuite) TestLocalLogoutRedirect(c *check.C) {
107 s.setupFederation("")
108 expURL := s.cluster.Services.Workbench1.ExternalURL
109 opts := arvados.LogoutOptions{ReturnTo: expURL.String()}
110 resp, err := s.fed.Logout(s.ctx, opts)
111 c.Check(err, check.IsNil)
112 c.Check(resp.RedirectLocation, check.Equals, expURL.String())
115 func (s *LogoutSuite) TestLocalLogoutBadRequestError(c *check.C) {
116 s.setupFederation("")
117 returnTo := s.badReturnURL("TestLocalLogoutBadRequestError")
118 opts := arvados.LogoutOptions{ReturnTo: returnTo.String()}
119 _, err := s.fed.Logout(s.ctx, opts)
120 c.Check(err, check.NotNil)
123 func (s *LogoutSuite) TestRemoteLogoutRedirect(c *check.C) {
124 s.setupFederation("zhome")
125 redirect := url.URL{Scheme: "https", Host: "example.com"}
126 loginStub := s.setupStub(c, "zhome", &redirect, nil)
127 returnTo := s.goodReturnURL("TestRemoteLogoutRedirect")
128 resp, err := s.fed.Logout(s.ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
129 c.Check(err, check.IsNil)
130 c.Check(resp.RedirectLocation, check.Equals, redirect.String())
131 loginStub.CheckCalls(c, returnTo)
134 func (s *LogoutSuite) TestRemoteLogoutError(c *check.C) {
135 s.setupFederation("zhome")
136 expErr := errors.New("TestRemoteLogoutError expErr")
137 loginStub := s.setupStub(c, "zhome", emptyURL, expErr)
138 returnTo := s.goodReturnURL("TestRemoteLogoutError")
139 _, err := s.fed.Logout(s.ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
140 c.Check(err, check.Equals, expErr)
141 loginStub.CheckCalls(c, returnTo)
144 func (s *LogoutSuite) TestRemoteLogoutLocalRedirect(c *check.C) {
145 s.setupFederation("zhome")
146 loginStub := s.setupStub(c, "zhome", emptyURL, nil)
147 redirect := url.URL{Scheme: "https", Host: "example.com"}
148 localStub := s.setupStub(c, "aaaaa", &redirect, nil)
149 resp, err := s.fed.Logout(s.ctx, arvados.LogoutOptions{})
150 c.Check(err, check.IsNil)
151 c.Check(resp.RedirectLocation, check.Equals, redirect.String())
152 // emptyURL to match the empty LogoutOptions
153 loginStub.CheckCalls(c, emptyURL)
154 localStub.CheckCalls(c, emptyURL)
157 func (s *LogoutSuite) TestRemoteLogoutLocalError(c *check.C) {
158 s.setupFederation("zhome")
159 expErr := errors.New("TestRemoteLogoutLocalError expErr")
160 loginStub := s.setupStub(c, "zhome", emptyURL, nil)
161 localStub := s.setupStub(c, "aaaaa", emptyURL, expErr)
162 _, err := s.fed.Logout(s.ctx, arvados.LogoutOptions{})
163 c.Check(err, check.Equals, expErr)
164 loginStub.CheckCalls(c, emptyURL)
165 localStub.CheckCalls(c, emptyURL)
168 func (s *LogoutSuite) TestV2TokenRedirect(c *check.C) {
169 s.setupFederation("")
170 redirect := url.URL{Scheme: "https", Host: "example.com"}
171 returnTo := s.goodReturnURL("TestV2TokenRedirect")
172 localErr := errors.New("TestV2TokenRedirect error")
173 tokenStub := s.setupStub(c, "zzzzz", &redirect, nil)
174 s.setupStub(c, "aaaaa", emptyURL, localErr)
175 tokens := []string{s.v2Token("zzzzz")}
176 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
177 resp, err := s.fed.Logout(ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
178 c.Check(err, check.IsNil)
179 c.Check(resp.RedirectLocation, check.Equals, redirect.String())
180 tokenStub.CheckCalls(c, returnTo)
183 func (s *LogoutSuite) TestV2TokenError(c *check.C) {
184 s.setupFederation("")
185 returnTo := s.goodReturnURL("TestV2TokenError")
186 tokenErr := errors.New("TestV2TokenError error")
187 tokenStub := s.setupStub(c, "zzzzz", emptyURL, tokenErr)
188 s.setupStub(c, "aaaaa", emptyURL, nil)
189 tokens := []string{s.v2Token("zzzzz")}
190 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
191 _, err := s.fed.Logout(ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
192 c.Check(err, check.Equals, tokenErr)
193 tokenStub.CheckCalls(c, returnTo)
196 func (s *LogoutSuite) TestV2TokenLocalRedirect(c *check.C) {
197 s.setupFederation("")
198 redirect := url.URL{Scheme: "https", Host: "example.com"}
199 tokenStub := s.setupStub(c, "zzzzz", emptyURL, nil)
200 localStub := s.setupStub(c, "aaaaa", &redirect, nil)
201 tokens := []string{s.v2Token("zzzzz")}
202 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
203 resp, err := s.fed.Logout(ctx, arvados.LogoutOptions{})
204 c.Check(err, check.IsNil)
205 c.Check(resp.RedirectLocation, check.Equals, redirect.String())
206 tokenStub.CheckCalls(c, emptyURL)
207 localStub.CheckCalls(c, emptyURL)
210 func (s *LogoutSuite) TestV2TokenLocalError(c *check.C) {
211 s.setupFederation("")
212 tokenErr := errors.New("TestV2TokenLocalError error")
213 tokenStub := s.setupStub(c, "zzzzz", emptyURL, nil)
214 localStub := s.setupStub(c, "aaaaa", emptyURL, tokenErr)
215 tokens := []string{s.v2Token("zzzzz")}
216 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
217 _, err := s.fed.Logout(ctx, arvados.LogoutOptions{})
218 c.Check(err, check.Equals, tokenErr)
219 tokenStub.CheckCalls(c, emptyURL)
220 localStub.CheckCalls(c, emptyURL)
223 func (s *LogoutSuite) TestV2LocalTokenRedirect(c *check.C) {
224 s.setupFederation("")
225 redirect := url.URL{Scheme: "https", Host: "example.com"}
226 returnTo := s.goodReturnURL("TestV2LocalTokenRedirect")
227 localStub := s.setupStub(c, "aaaaa", &redirect, nil)
228 tokens := []string{s.v2Token("aaaaa")}
229 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
230 resp, err := s.fed.Logout(ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
231 c.Check(err, check.IsNil)
232 c.Check(resp.RedirectLocation, check.Equals, redirect.String())
233 localStub.CheckCalls(c, returnTo)
236 func (s *LogoutSuite) TestV2LocalTokenError(c *check.C) {
237 s.setupFederation("")
238 returnTo := s.goodReturnURL("TestV2LocalTokenError")
239 tokenErr := errors.New("TestV2LocalTokenError error")
240 localStub := s.setupStub(c, "aaaaa", emptyURL, tokenErr)
241 tokens := []string{s.v2Token("aaaaa")}
242 ctx := auth.NewContext(s.ctx, &auth.Credentials{Tokens: tokens})
243 _, err := s.fed.Logout(ctx, arvados.LogoutOptions{ReturnTo: returnTo.String()})
244 c.Check(err, check.Equals, tokenErr)
245 localStub.CheckCalls(c, returnTo)