67 lines
1.6 KiB
Go
Executable file
67 lines
1.6 KiB
Go
Executable file
package oidc
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
phttp "github.com/coreos/go-oidc/http"
|
|
"github.com/coreos/go-oidc/jose"
|
|
"github.com/coreos/go-oidc/key"
|
|
)
|
|
|
|
// DefaultPublicKeySetTTL is the default TTL set on the PublicKeySet if no
|
|
// Cache-Control header is provided by the JWK Set document endpoint.
|
|
const DefaultPublicKeySetTTL = 24 * time.Hour
|
|
|
|
// NewRemotePublicKeyRepo is responsible for fetching the JWK Set document.
|
|
func NewRemotePublicKeyRepo(hc phttp.Client, ep string) *remotePublicKeyRepo {
|
|
return &remotePublicKeyRepo{hc: hc, ep: ep}
|
|
}
|
|
|
|
type remotePublicKeyRepo struct {
|
|
hc phttp.Client
|
|
ep string
|
|
}
|
|
|
|
// Get returns a PublicKeySet fetched from the JWK Set document endpoint. A TTL
|
|
// is set on the Key Set to avoid it having to be re-retrieved for every
|
|
// encryption event. This TTL is typically controlled by the endpoint returning
|
|
// a Cache-Control header, but defaults to 24 hours if no Cache-Control header
|
|
// is found.
|
|
func (r *remotePublicKeyRepo) Get() (key.KeySet, error) {
|
|
req, err := http.NewRequest("GET", r.ep, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
resp, err := r.hc.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var d struct {
|
|
Keys []jose.JWK `json:"keys"`
|
|
}
|
|
if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(d.Keys) == 0 {
|
|
return nil, errors.New("zero keys in response")
|
|
}
|
|
|
|
ttl, ok, err := phttp.Cacheable(resp.Header)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
ttl = DefaultPublicKeySetTTL
|
|
}
|
|
|
|
exp := time.Now().UTC().Add(ttl)
|
|
ks := key.NewPublicKeySet(d.Keys, exp)
|
|
return ks, nil
|
|
}
|