github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+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 113 request *cloudcontroller.Request 114 115 executeErr error 116 ) 117 118 BeforeEach(func() { 119 expectedBody = "this body content should be preserved" 120 body := strings.NewReader(expectedBody) 121 request = cloudcontroller.NewRequest(&http.Request{ 122 Header: http.Header{}, 123 Body: ioutil.NopCloser(body), 124 }, body) 125 126 makeCount := 0 127 fakeConnection.MakeStub = func(request *cloudcontroller.Request, response *cloudcontroller.Response) error { 128 body, err := ioutil.ReadAll(request.Body) 129 Expect(err).NotTo(HaveOccurred()) 130 Expect(string(body)).To(Equal(expectedBody)) 131 132 if makeCount == 0 { 133 makeCount += 1 134 return ccerror.InvalidAuthTokenError{} 135 } else { 136 return nil 137 } 138 } 139 140 inMemoryCache.SetAccessToken("what") 141 142 fakeClient.RefreshAccessTokenReturns( 143 uaa.RefreshToken{ 144 AccessToken: "foobar-2", 145 RefreshToken: "bananananananana", 146 Type: "bearer", 147 }, 148 nil, 149 ) 150 }) 151 152 JustBeforeEach(func() { 153 executeErr = wrapper.Make(request, nil) 154 }) 155 156 It("should refresh the token", func() { 157 Expect(executeErr).ToNot(HaveOccurred()) 158 Expect(fakeClient.RefreshAccessTokenCallCount()).To(Equal(1)) 159 }) 160 161 It("should resend the request", func() { 162 Expect(executeErr).ToNot(HaveOccurred()) 163 Expect(fakeConnection.MakeCallCount()).To(Equal(2)) 164 165 request, _ := fakeConnection.MakeArgsForCall(1) 166 Expect(request.Header.Get("Authorization")).To(Equal("bearer foobar-2")) 167 }) 168 169 It("should save the refresh token", func() { 170 Expect(executeErr).ToNot(HaveOccurred()) 171 Expect(inMemoryCache.RefreshToken()).To(Equal("bananananananana")) 172 }) 173 174 Context("when a PipeSeekError is returned from ResetBody", func() { 175 BeforeEach(func() { 176 body, writer := cloudcontroller.NewPipeBomb() 177 req, err := http.NewRequest(http.MethodGet, "https://foo.bar.com/banana", body) 178 Expect(err).NotTo(HaveOccurred()) 179 request = cloudcontroller.NewRequest(req, body) 180 181 go func() { 182 defer GinkgoRecover() 183 184 _, err := writer.Write([]byte(expectedBody)) 185 Expect(err).NotTo(HaveOccurred()) 186 err = writer.Close() 187 Expect(err).NotTo(HaveOccurred()) 188 }() 189 }) 190 191 It("set the err on PipeSeekError", func() { 192 Expect(executeErr).To(MatchError(ccerror.PipeSeekError{Err: ccerror.InvalidAuthTokenError{}})) 193 }) 194 }) 195 }) 196 }) 197 })