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  })