github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/api/cloudcontroller/wrapper/uaa_authentication_test.go (about) 1 package wrapper_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "net/http" 7 "strings" 8 9 "code.cloudfoundry.org/cli/api/cloudcontroller" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/cloudcontrollerfakes" 12 . "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper" 13 "code.cloudfoundry.org/cli/api/cloudcontroller/wrapper/wrapperfakes" 14 "code.cloudfoundry.org/cli/api/uaa" 15 "code.cloudfoundry.org/cli/api/uaa/wrapper/util" 16 17 . "github.com/onsi/ginkgo" 18 . "github.com/onsi/gomega" 19 ) 20 21 var _ = Describe("UAA Authentication", func() { 22 var ( 23 fakeConnection *cloudcontrollerfakes.FakeConnection 24 fakeClient *wrapperfakes.FakeUAAClient 25 inMemoryCache *util.InMemoryCache 26 27 wrapper cloudcontroller.Connection 28 request *cloudcontroller.Request 29 inner *UAAAuthentication 30 ) 31 32 BeforeEach(func() { 33 fakeConnection = new(cloudcontrollerfakes.FakeConnection) 34 fakeClient = new(wrapperfakes.FakeUAAClient) 35 inMemoryCache = util.NewInMemoryTokenCache() 36 inMemoryCache.SetAccessToken("a-ok") 37 38 inner = NewUAAAuthentication(fakeClient, inMemoryCache) 39 wrapper = inner.Wrap(fakeConnection) 40 41 request = &cloudcontroller.Request{ 42 Request: &http.Request{ 43 Header: http.Header{}, 44 }, 45 } 46 }) 47 48 Describe("Make", func() { 49 Context("when the client is nil", func() { 50 BeforeEach(func() { 51 inner.SetClient(nil) 52 53 fakeConnection.MakeReturns(ccerror.InvalidAuthTokenError{}) 54 }) 55 56 It("calls the connection without any side effects", func() { 57 err := wrapper.Make(request, nil) 58 Expect(err).To(MatchError(ccerror.InvalidAuthTokenError{})) 59 60 Expect(fakeClient.RefreshAccessTokenCallCount()).To(Equal(0)) 61 Expect(fakeConnection.MakeCallCount()).To(Equal(1)) 62 }) 63 }) 64 65 Context("when the token is valid", func() { 66 It("adds authentication headers", func() { 67 err := wrapper.Make(request, nil) 68 Expect(err).ToNot(HaveOccurred()) 69 70 Expect(fakeConnection.MakeCallCount()).To(Equal(1)) 71 authenticatedRequest, _ := fakeConnection.MakeArgsForCall(0) 72 headers := authenticatedRequest.Header 73 Expect(headers["Authorization"]).To(ConsistOf([]string{"a-ok"})) 74 }) 75 76 Context("when the request already has headers", func() { 77 It("preserves existing headers", func() { 78 request.Header.Add("Existing", "header") 79 err := wrapper.Make(request, nil) 80 Expect(err).ToNot(HaveOccurred()) 81 82 Expect(fakeConnection.MakeCallCount()).To(Equal(1)) 83 authenticatedRequest, _ := fakeConnection.MakeArgsForCall(0) 84 headers := authenticatedRequest.Header 85 Expect(headers["Existing"]).To(ConsistOf([]string{"header"})) 86 }) 87 }) 88 89 Context("when the wrapped connection returns nil", func() { 90 It("returns nil", func() { 91 fakeConnection.MakeReturns(nil) 92 93 err := wrapper.Make(request, nil) 94 Expect(err).ToNot(HaveOccurred()) 95 }) 96 }) 97 98 Context("when the wrapped connection returns an error", func() { 99 It("returns the error", func() { 100 innerError := errors.New("inner error") 101 fakeConnection.MakeReturns(innerError) 102 103 err := wrapper.Make(request, nil) 104 Expect(err).To(Equal(innerError)) 105 }) 106 }) 107 }) 108 109 Context("when the token is invalid", func() { 110 var ( 111 expectedBody string 112 request *cloudcontroller.Request 113 executeErr error 114 ) 115 116 BeforeEach(func() { 117 expectedBody = "this body content should be preserved" 118 body := strings.NewReader(expectedBody) 119 request = cloudcontroller.NewRequest(&http.Request{ 120 Header: http.Header{}, 121 Body: ioutil.NopCloser(body), 122 }, body) 123 124 makeCount := 0 125 fakeConnection.MakeStub = func(request *cloudcontroller.Request, response *cloudcontroller.Response) error { 126 body, err := ioutil.ReadAll(request.Body) 127 Expect(err).NotTo(HaveOccurred()) 128 Expect(string(body)).To(Equal(expectedBody)) 129 130 if makeCount == 0 { 131 makeCount += 1 132 return ccerror.InvalidAuthTokenError{} 133 } else { 134 return nil 135 } 136 } 137 138 inMemoryCache.SetAccessToken("what") 139 140 fakeClient.RefreshAccessTokenReturns( 141 uaa.RefreshedTokens{ 142 AccessToken: "foobar-2", 143 RefreshToken: "bananananananana", 144 Type: "bearer", 145 }, 146 nil, 147 ) 148 }) 149 150 JustBeforeEach(func() { 151 executeErr = wrapper.Make(request, nil) 152 }) 153 154 It("should refresh the token", func() { 155 Expect(executeErr).ToNot(HaveOccurred()) 156 Expect(fakeClient.RefreshAccessTokenCallCount()).To(Equal(1)) 157 }) 158 159 It("should resend the request", func() { 160 Expect(executeErr).ToNot(HaveOccurred()) 161 Expect(fakeConnection.MakeCallCount()).To(Equal(2)) 162 163 requestArg, _ := fakeConnection.MakeArgsForCall(1) 164 Expect(requestArg.Header.Get("Authorization")).To(Equal("bearer foobar-2")) 165 }) 166 167 It("should save the refresh token", func() { 168 Expect(executeErr).ToNot(HaveOccurred()) 169 Expect(inMemoryCache.RefreshToken()).To(Equal("bananananananana")) 170 }) 171 172 Context("when a PipeSeekError is returned from ResetBody", func() { 173 BeforeEach(func() { 174 body, writer := cloudcontroller.NewPipeBomb() 175 req, err := http.NewRequest(http.MethodGet, "https://foo.bar.com/banana", body) 176 Expect(err).NotTo(HaveOccurred()) 177 request = cloudcontroller.NewRequest(req, body) 178 179 go func() { 180 defer GinkgoRecover() 181 182 _, err := writer.Write([]byte(expectedBody)) 183 Expect(err).NotTo(HaveOccurred()) 184 err = writer.Close() 185 Expect(err).NotTo(HaveOccurred()) 186 }() 187 }) 188 189 It("set the err on PipeSeekError", func() { 190 Expect(executeErr).To(MatchError(ccerror.PipeSeekError{Err: ccerror.InvalidAuthTokenError{}})) 191 }) 192 }) 193 }) 194 }) 195 })