Merge pull request #51 from 30x/accesstoken-endpoint
Add accesstoken endpoint for gateway to use in microservice requests
diff --git a/api.go b/api.go
new file mode 100644
index 0000000..233c318
--- /dev/null
+++ b/api.go
@@ -0,0 +1,62 @@
+package apidApigeeSync
+
+import (
+ "encoding/json"
+ "github.com/30x/apid-core"
+ "net/http"
+ "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"`
+}
diff --git a/change_test.go b/change_test.go
index 383bff6..67331c4 100644
--- a/change_test.go
+++ b/change_test.go
@@ -155,6 +155,10 @@
invalidateChan chan bool
}
+func (t *dummyTokenManager) getTokenReadyChannel() <-chan bool {
+ return nil
+}
+
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..8ef331c 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..46e52cd 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"`