github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+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  	"github.com/liamawhite/cli-with-i18n/api/cloudcontroller"
    10  	"github.com/liamawhite/cli-with-i18n/api/cloudcontroller/ccerror"
    11  	"github.com/liamawhite/cli-with-i18n/api/cloudcontroller/cloudcontrollerfakes"
    12  	. "github.com/liamawhite/cli-with-i18n/api/cloudcontroller/wrapper"
    13  	"github.com/liamawhite/cli-with-i18n/api/cloudcontroller/wrapper/wrapperfakes"
    14  	"github.com/liamawhite/cli-with-i18n/api/uaa"
    15  	"github.com/liamawhite/cli-with-i18n/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  })