github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/uaa/wrapper/uaa_authentication.go (about) 1 package wrapper 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "net/http" 7 "strings" 8 9 "code.cloudfoundry.org/cli/api/uaa" 10 ) 11 12 //go:generate counterfeiter . UAAClient 13 14 // UAAClient is the interface for getting a valid access token 15 type UAAClient interface { 16 RefreshAccessToken(refreshToken string) (uaa.RefreshToken, error) 17 } 18 19 //go:generate counterfeiter . TokenCache 20 21 // TokenCache is where the UAA token information is stored. 22 type TokenCache interface { 23 AccessToken() string 24 RefreshToken() string 25 SetAccessToken(token string) 26 SetRefreshToken(token string) 27 } 28 29 // UAAAuthentication wraps connections and adds authentication headers to all 30 // requests 31 type UAAAuthentication struct { 32 connection uaa.Connection 33 client UAAClient 34 cache TokenCache 35 } 36 37 // NewUAAAuthentication returns a pointer to a UAAAuthentication wrapper with 38 // the client and token cache. 39 func NewUAAAuthentication(client UAAClient, cache TokenCache) *UAAAuthentication { 40 return &UAAAuthentication{ 41 client: client, 42 cache: cache, 43 } 44 } 45 46 // Wrap sets the connection on the UAAAuthentication and returns itself 47 func (t *UAAAuthentication) Wrap(innerconnection uaa.Connection) uaa.Connection { 48 t.connection = innerconnection 49 return t 50 } 51 52 // Make adds authentication headers to the passed in request and then calls the 53 // wrapped connection's Make 54 func (t *UAAAuthentication) Make(request *http.Request, passedResponse *uaa.Response) error { 55 var err error 56 var rawRequestBody []byte 57 58 if request.Body != nil { 59 rawRequestBody, err = ioutil.ReadAll(request.Body) 60 defer request.Body.Close() 61 if err != nil { 62 return err 63 } 64 65 request.Body = ioutil.NopCloser(bytes.NewBuffer(rawRequestBody)) 66 67 if skipAuthenticationHeader(request, rawRequestBody) { 68 return t.connection.Make(request, passedResponse) 69 } 70 } 71 72 request.Header.Set("Authorization", t.cache.AccessToken()) 73 74 err = t.connection.Make(request, passedResponse) 75 if _, ok := err.(uaa.InvalidAuthTokenError); ok { 76 var token uaa.RefreshToken 77 token, err = t.client.RefreshAccessToken(t.cache.RefreshToken()) 78 if err != nil { 79 return err 80 } 81 82 t.cache.SetAccessToken(token.AuthorizationToken()) 83 t.cache.SetRefreshToken(token.RefreshToken) 84 85 if rawRequestBody != nil { 86 request.Body = ioutil.NopCloser(bytes.NewBuffer(rawRequestBody)) 87 } 88 request.Header.Set("Authorization", t.cache.AccessToken()) 89 return t.connection.Make(request, passedResponse) 90 } 91 92 return err 93 } 94 95 // The authentication header is not added to token refresh requests or login 96 // requests. 97 func skipAuthenticationHeader(request *http.Request, body []byte) bool { 98 stringBody := string(body) 99 100 return strings.Contains(request.URL.String(), "/oauth/token") && 101 request.Method == http.MethodPost && 102 (strings.Contains(stringBody, "grant_type=refresh_token") || 103 strings.Contains(stringBody, "grant_type=password")) 104 }