This is an automated email from the ASF dual-hosted git repository.

ocket8888 pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/5.1.x by this push:
     new fac4746  Prevent looping in case of login failure (#5790)
fac4746 is described below

commit fac47462bdef9cc0f1aa4cf70f6d0a6fdbe655cf
Author: Srijeet Chatterjee <[email protected]>
AuthorDate: Tue Apr 27 16:09:10 2021 -0600

    Prevent looping in case of login failure (#5790)
---
 CHANGELOG.md                     |  1 +
 traffic_ops/v3-client/session.go | 40 +++++++++++++++++++++++-----------------
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f7d6fd7..8c0eab0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - Fixed Traffic Monitor to report `ONLINE` caches as available.
 - [#5744](https://github.com/apache/trafficcontrol/issues/5744) - Sort TM 
Delivery Service States page by DS name
 - [#5724](https://github.com/apache/trafficcontrol/issues/5724) - Set XMPPID 
to hostname if the server had none, don't error on server update when XMPPID is 
empty
+- [#5739](https://github.com/apache/trafficcontrol/issues/5739) - Prevent 
looping in case of a failed login attempt
 
 ## [5.1.1] - 2021-03-19
 ### Added
diff --git a/traffic_ops/v3-client/session.go b/traffic_ops/v3-client/session.go
index 2e0f4c9..390cc3c 100644
--- a/traffic_ops/v3-client/session.go
+++ b/traffic_ops/v3-client/session.go
@@ -212,7 +212,7 @@ func (to *Session) login() (net.Addr, error) {
        // Can't use req() because it retries login failures, which would be an 
infinite loop.
        reqF := composeReqFuncs(makeRequestWithHeader, []MidReqF{reqTryLatest, 
reqFallback, reqAPI})
 
-       reqInf, err := reqF(to, http.MethodPost, path, body, nil, &alerts)
+       reqInf, err := reqF(to, http.MethodPost, path, body, nil, &alerts, true)
        if err != nil {
                return reqInf.RemoteAddr, fmt.Errorf("Login error %v, alerts 
string: %+v", err, alerts)
        }
@@ -425,7 +425,7 @@ func (to *Session) errUnlessOKOrNotModified(resp 
*http.Response, remoteAddr net.
 
 func (to *Session) getURL(path string) string { return to.URL + path }
 
-type ReqF func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}) (ReqInf, error)
+type ReqF func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}, raw bool) (ReqInf, error)
 
 type MidReqF func(ReqF) ReqF
 
@@ -442,7 +442,7 @@ func composeReqFuncs(reqF ReqF, middleware []MidReqF) ReqF {
 // reqTryLatest will re-set to.latestSupportedAPI to the latest, if it's less 
than the latest and to.apiVerCheckInterval has passed.
 // This does not fallback, so it should generally be composed with reqFallback.
 func reqTryLatest(reqF ReqF) ReqF {
-       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}) (ReqInf, error) {
+       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}, raw bool) (ReqInf, error) {
                if to.apiVerCheckInterval == 0 {
                        // Session could have been default-initialized rather 
than created with a func, so we need to check here, not just in login funcs.
                        to.apiVerCheckInterval = DefaultAPIVersionCheckInterval
@@ -460,7 +460,7 @@ func reqTryLatest(reqF ReqF) ReqF {
                        to.lastAPIVerCheck = time.Now().Add(time.Hour * 24 * 
365)
                        defer func() { to.lastAPIVerCheck = time.Now() }()
                }
-               return reqF(to, method, path, body, header, response)
+               return reqF(to, method, path, body, header, response, raw)
        }
 }
 
@@ -470,15 +470,15 @@ func reqTryLatest(reqF ReqF) ReqF {
 // This is designed to handle expired sessions, when the time between requests 
is longer than the session expiration;
 // it does not do perpetual retry.
 func reqLogin(reqF ReqF) ReqF {
-       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}) (ReqInf, error) {
-               inf, err := reqF(to, method, path, body, header, response)
+       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}, raw bool) (ReqInf, error) {
+               inf, err := reqF(to, method, path, body, header, response, raw)
                if inf.StatusCode != http.StatusUnauthorized && inf.StatusCode 
!= http.StatusForbidden {
                        return inf, err
                }
                if _, lerr := to.login(); lerr != nil {
                        return inf, err
                }
-               return reqF(to, method, path, body, header, response)
+               return reqF(to, method, path, body, header, response, raw)
        }
 }
 
@@ -486,9 +486,9 @@ func reqLogin(reqF ReqF) ReqF {
 // falls back to the previous and retries, recursively.
 // If all supported versions fail, the last response error is returned.
 func reqFallback(reqF ReqF) ReqF {
-       var fallbackFunc func(to *Session, method string, path string, body 
interface{}, header http.Header, response interface{}) (ReqInf, error)
-       fallbackFunc = func(to *Session, method string, path string, body 
interface{}, header http.Header, response interface{}) (ReqInf, error) {
-               inf, err := reqF(to, method, path, body, header, response)
+       var fallbackFunc func(to *Session, method string, path string, body 
interface{}, header http.Header, response interface{}, raw bool) (ReqInf, error)
+       fallbackFunc = func(to *Session, method string, path string, body 
interface{}, header http.Header, response interface{}, raw bool) (ReqInf, 
error) {
+               inf, err := reqF(to, method, path, body, header, response, 
false)
                if err == nil {
                        return inf, err
                }
@@ -512,7 +512,7 @@ func reqFallback(reqF ReqF) ReqF {
                }
                to.latestSupportedAPI = apiVersions[nextAPIVerI]
 
-               return fallbackFunc(to, method, path, body, header, response)
+               return fallbackFunc(to, method, path, body, header, response, 
false)
        }
        return fallbackFunc
 }
@@ -524,9 +524,9 @@ func reqFallback(reqF ReqF) ReqF {
 // and this will request '/api/3.1/deliveryservices'.
 //
 func reqAPI(reqF ReqF) ReqF {
-       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}) (ReqInf, error) {
+       return func(to *Session, method string, path string, body interface{}, 
header http.Header, response interface{}, raw bool) (ReqInf, error) {
                path = to.APIBase() + path
-               return reqF(to, method, path, body, header, response)
+               return reqF(to, method, path, body, header, response, raw)
        }
 }
 
@@ -543,18 +543,24 @@ func reqAPI(reqF ReqF) ReqF {
 //
 // To request the bytes without deserializing, pass a *[]byte response.
 //
-func makeRequestWithHeader(to *Session, method, path string, body interface{}, 
header http.Header, response interface{}) (ReqInf, error) {
+func makeRequestWithHeader(to *Session, method, path string, body interface{}, 
header http.Header, response interface{}, raw bool) (ReqInf, error) {
        var remoteAddr net.Addr
+       var resp *http.Response
+       var err error
        reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: 
remoteAddr}
        var reqBody []byte
-       var err error
+
        if body != nil {
                reqBody, err = json.Marshal(body)
                if err != nil {
                        return reqInf, errors.New("marshalling request body: " 
+ err.Error())
                }
        }
-       resp, remoteAddr, err := to.request(method, path, reqBody, header)
+       if raw {
+               resp, remoteAddr, err = to.RawRequestWithHdr(method, path, 
reqBody, header)
+       } else {
+               resp, remoteAddr, err = to.request(method, path, reqBody, 
header)
+       }
        reqInf.RemoteAddr = remoteAddr
        if resp != nil {
                reqInf.StatusCode = resp.StatusCode
@@ -600,7 +606,7 @@ func (to *Session) del(path string, header http.Header, 
response interface{}) (R
 
 func (to *Session) req(method string, path string, body interface{}, header 
http.Header, response interface{}) (ReqInf, error) {
        reqF := composeReqFuncs(makeRequestWithHeader, []MidReqF{reqTryLatest, 
reqFallback, reqAPI, reqLogin})
-       return reqF(to, method, path, body, header, response)
+       return reqF(to, method, path, body, header, response, false)
 }
 
 // request performs the HTTP request to Traffic Ops, trying to refresh the 
cookie if an Unauthorized or Forbidden code is received. It only tries once. If 
the login fails, the original Unauthorized/Forbidden response is returned. If 
the login succeeds and the subsequent re-request fails, the re-request's 
response is returned even if it's another Unauthorized/Forbidden.

Reply via email to