Add accesstoken endpoint for gateway to use in microservice requests
diff --git a/api.go b/api.go new file mode 100644 index 0000000..822828c --- /dev/null +++ b/api.go
@@ -0,0 +1,62 @@ +package apidApigeeSync + +import ( + "github.com/30x/apid-core" + "net/http" + "encoding/json" + "strconv" + "time" +) + +const tokenEndpoint = "/accesstoken" + +func InitAPI(services apid.Services) { + services.API().HandleFunc(tokenEndpoint, getAccessToken).Methods("GET") +} + +func getAccessToken(w http.ResponseWriter, r *http.Request) { + b := r.URL.Query().Get("block") + var timeout int + if b != "" { + var err error + timeout, err = strconv.Atoi(b) + if err != nil { + writeError(w, http.StatusBadRequest, "bad block value, must be number of seconds") + return + } + } + log.Debugf("api timeout: %d", timeout) + ifNoneMatch := r.Header.Get("If-None-Match") + + if apidTokenManager.getBearerToken() != ifNoneMatch { + w.Write([]byte(apidTokenManager.getBearerToken())) + return + } + + select { + case <-apidTokenManager.getTokenReadyChannel(): + w.Write([]byte(apidTokenManager.getBearerToken())) + case <-time.After(time.Duration(timeout) * time.Second): + w.WriteHeader(http.StatusNotModified) + } +} + +func writeError(w http.ResponseWriter, status int, reason string) { + w.WriteHeader(status) + e := errorResponse{ + ErrorCode: status, + Reason: reason, + } + bytes, err := json.Marshal(e) + if err != nil { + log.Errorf("unable to marshal errorResponse: %v", err) + } else { + w.Write(bytes) + } + log.Debugf("sending %d error to client: %s", status, reason) +} + +type errorResponse struct { + ErrorCode int `json:"errorCode"` + Reason string `json:"reason"` +} \ No newline at end of file
diff --git a/change_test.go b/change_test.go index 383bff6..09b4a50 100644 --- a/change_test.go +++ b/change_test.go
@@ -155,6 +155,10 @@ invalidateChan chan bool } +func (t *dummyTokenManager) getTokenReadyChannel() chan bool { + return make(chan bool) +} + func (t *dummyTokenManager) getBearerToken() string { return "" }
diff --git a/init.go b/init.go index 245d4af..1ad67fd 100644 --- a/init.go +++ b/init.go
@@ -189,6 +189,7 @@ */ events.ListenOnceFunc(apid.SystemEventsSelector, postInitPlugins) + InitAPI(services) log.Debug("end init") return pluginData, nil
diff --git a/managerInterfaces.go b/managerInterfaces.go index 5022bdd..7db7130 100644 --- a/managerInterfaces.go +++ b/managerInterfaces.go
@@ -26,6 +26,7 @@ close() getRetrieveNewTokenClosure(*url.URL) func(chan bool) error start() + getTokenReadyChannel() chan bool } type snapShotManager interface {
diff --git a/token.go b/token.go index 1612025..0533043 100644 --- a/token.go +++ b/token.go
@@ -49,6 +49,7 @@ invalidateTokenChan: make(chan bool), returnTokenChan: make(chan *OauthToken), invalidateDone: make(chan bool), + tokenUpdatedChan: make(chan bool, 1), isClosed: &isClosedInt, } return t @@ -64,6 +65,7 @@ refreshTimer <-chan time.Time returnTokenChan chan *OauthToken invalidateDone chan bool + tokenUpdatedChan chan bool } func (t *simpleTokenManager) start() { @@ -218,10 +220,21 @@ t.token = &token config.Set(configBearerToken, token.AccessToken) + //don't block on the buffered channel. that means there is already a signal to serve new token + select { + case t.tokenUpdatedChan <- true: + default: + log.Debug("Token refresh notification already sent") + } + return nil } } +func (t *simpleTokenManager) getTokenReadyChannel() chan bool { + return t.tokenUpdatedChan +} + type OauthToken struct { IssuedAt int64 `json:"issuedAt"` AppName string `json:"applicationName"`