github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+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  		// The authentication header is not added to the token refresh request.
    68  		if strings.Contains(request.URL.String(), "/oauth/token") &&
    69  			request.Method == http.MethodPost &&
    70  			strings.Contains(string(rawRequestBody), "grant_type=refresh_token") {
    71  			return t.connection.Make(request, passedResponse)
    72  		}
    73  	}
    74  
    75  	request.Header.Set("Authorization", t.cache.AccessToken())
    76  
    77  	err = t.connection.Make(request, passedResponse)
    78  	if _, ok := err.(uaa.InvalidAuthTokenError); ok {
    79  		var token uaa.RefreshToken
    80  		token, err = t.client.RefreshAccessToken(t.cache.RefreshToken())
    81  		if err != nil {
    82  			return err
    83  		}
    84  
    85  		t.cache.SetAccessToken(token.AuthorizationToken())
    86  		t.cache.SetRefreshToken(token.RefreshToken)
    87  
    88  		if rawRequestBody != nil {
    89  			request.Body = ioutil.NopCloser(bytes.NewBuffer(rawRequestBody))
    90  		}
    91  		request.Header.Set("Authorization", t.cache.AccessToken())
    92  		return t.connection.Make(request, passedResponse)
    93  	}
    94  
    95  	return err
    96  }