func TestHandler(t *testing.T) { mockKeys := mockValidKeys() kl := &mockKeyLoader{theKeys: mockKeys} h := NewHandler(kl) w := httptest.NewRecorder() r, _ := http.NewRequest("GET", "http://example.com/oauth2/v3/keys", nil) h.ServeHTTP(w, r) if w.Code != http.StatusOK { t.Errorf("Wrong status code. Wanted %q, got %q", http.StatusText(http.StatusOK), http.StatusText(w.Code)) } jwks := new(jwk.JSONWebKeySet) if err := json.NewDecoder(w.Body).Decode(jwks); err != nil { t.Error("Failed to recover the response to a JWKS object") } m := jwks.ToMap() if !reflect.DeepEqual(m, mockKeys) { t.Error("JWKS doesn't match the original") } }
// Example: https://www.googleapis.com/oauth2/v3/certs func (kl *cachingOpenIDProviderLoader) refreshKeys() { log.Println("Refreshing keys..") log.Println("Loading configuration..") c, err := kl.loadConfiguration() if err != nil { log.Printf("Failed to get configuration from %q. %s\n", kl.url, err) return } log.Println("Configuration loaded successfully, loading JWKS..") resp, err := breaker.Get("loadKeys", c.JwksURI) if err != nil { log.Println("Failed to get JWKS from ", c.JwksURI) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Failed to read JWKS response body from %q: %v\n", c.JwksURI, err) return } log.Println("JWKS loaded successfully, parsing JWKS..") jwks := new(jwk.JSONWebKeySet) if err = json.Unmarshal(body, jwks); err != nil { log.Println("Failed to parse JWKS: ", err) return } // safety first: only remove public keys if our newly // received list contains at least one public key! // (we don't want our tokeninfo to run out of public keys // just because somebody cleared the provider database) numKeys := len(jwks.Keys) if numKeys < 1 { log.Println("No JWKS currently in the OpenID provider") if c, ok := metrics.DefaultRegistry.GetOrRegister(metricsNoKeysError, metrics.NewCounter).(metrics.Counter); ok { c.Inc(1) } return } if g, ok := metrics.DefaultRegistry.GetOrRegister(metricsNumKeys, metrics.NewGauge).(metrics.Gauge); ok { g.Update(int64(numKeys)) } newKeys := jwks.ToMap() for kid, k := range newKeys { key := k.(jwk.JSONWebKey) existing := kl.keyCache.Get(kid) if existing == nil { log.Printf("Received new public key %q (%s)\n", kid, key.Algorithm) } else if !reflect.DeepEqual(existing, key) { // this is potentially dangerous: the key contents changed.. // (but maybe the key wasn't used for signing yet, so it might be ok) log.Printf("Received a replacement public key for existing key %q (%s)", kid, key.Algorithm) } } log.Printf("Resetting key cache with %d key(s)..", numKeys) kl.keyCache.Reset(newKeys) log.Println("Refresh done..") }