github.com/cloudfoundry/cli@v7.1.0+incompatible/api/uaa/uaa_connection.go (about) 1 package uaa 2 3 import ( 4 "bytes" 5 "crypto/x509" 6 "encoding/json" 7 "io/ioutil" 8 "net" 9 "net/http" 10 "net/url" 11 "time" 12 13 "code.cloudfoundry.org/cli/util" 14 ) 15 16 // UAAConnection represents the connection to UAA 17 type UAAConnection struct { 18 HTTPClient *http.Client 19 } 20 21 // NewConnection returns a pointer to a new UAA Connection 22 func NewConnection(skipSSLValidation bool, disableKeepAlives bool, dialTimeout time.Duration) *UAAConnection { 23 tr := &http.Transport{ 24 DialContext: (&net.Dialer{ 25 KeepAlive: 30 * time.Second, 26 Timeout: dialTimeout, 27 }).DialContext, 28 DisableKeepAlives: disableKeepAlives, 29 Proxy: http.ProxyFromEnvironment, 30 TLSClientConfig: util.NewTLSConfig(nil, skipSSLValidation), 31 } 32 33 return &UAAConnection{ 34 HTTPClient: &http.Client{ 35 Transport: tr, 36 CheckRedirect: func(_ *http.Request, _ []*http.Request) error { 37 // This prevents redirects. When making a request to /oauth/authorize, 38 // the client should not follow redirects in order to obtain the ssh 39 // passcode. 40 return http.ErrUseLastResponse 41 }, 42 }, 43 } 44 } 45 46 // Make takes a passedRequest, converts it into an HTTP request and then 47 // executes it. The response is then injected into passedResponse. 48 func (connection *UAAConnection) Make(request *http.Request, passedResponse *Response) error { 49 // In case this function is called from a retry, passedResponse may already 50 // be populated with a previous response. We reset in case there's an HTTP 51 // error and we don't repopulate it in populateResponse. 52 passedResponse.reset() 53 54 response, err := connection.HTTPClient.Do(request) 55 if err != nil { 56 return connection.processRequestErrors(request, err) 57 } 58 59 return connection.populateResponse(response, passedResponse) 60 } 61 62 func (*UAAConnection) handleStatusCodes(response *http.Response, passedResponse *Response) error { 63 if response.StatusCode >= 400 { 64 return RawHTTPStatusError{ 65 StatusCode: response.StatusCode, 66 RawResponse: passedResponse.RawResponse, 67 } 68 } 69 70 return nil 71 } 72 73 func (connection *UAAConnection) populateResponse(response *http.Response, passedResponse *Response) error { 74 passedResponse.HTTPResponse = response 75 76 rawBytes, err := ioutil.ReadAll(response.Body) 77 defer response.Body.Close() 78 if err != nil { 79 return err 80 } 81 passedResponse.RawResponse = rawBytes 82 83 err = connection.handleStatusCodes(response, passedResponse) 84 if err != nil { 85 return err 86 } 87 88 if passedResponse.Result != nil { 89 decoder := json.NewDecoder(bytes.NewBuffer(passedResponse.RawResponse)) 90 decoder.UseNumber() 91 err = decoder.Decode(passedResponse.Result) 92 if err != nil { 93 return err 94 } 95 } 96 97 return nil 98 } 99 100 func (connection *UAAConnection) processRequestErrors(request *http.Request, err error) error { 101 switch e := err.(type) { 102 case *url.Error: 103 if _, ok := e.Err.(x509.UnknownAuthorityError); ok { 104 return UnverifiedServerError{ 105 URL: request.URL.String(), 106 } 107 } 108 return RequestError{Err: e} 109 default: 110 return err 111 } 112 }