Commit 5d58c743 authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #22304 from ericchiang/bump_go_oidc

Auto commit by PR queue bot
parents 5e50302a 8df55ddb
......@@ -271,23 +271,23 @@
},
{
"ImportPath": "github.com/coreos/go-oidc/http",
"Rev": "024cdeee09d02fb439eb55bc422e582ac115615b"
"Rev": "d7cb66526fffc811d602b6770581064f4b66b507"
},
{
"ImportPath": "github.com/coreos/go-oidc/jose",
"Rev": "024cdeee09d02fb439eb55bc422e582ac115615b"
"Rev": "d7cb66526fffc811d602b6770581064f4b66b507"
},
{
"ImportPath": "github.com/coreos/go-oidc/key",
"Rev": "024cdeee09d02fb439eb55bc422e582ac115615b"
"Rev": "d7cb66526fffc811d602b6770581064f4b66b507"
},
{
"ImportPath": "github.com/coreos/go-oidc/oauth2",
"Rev": "024cdeee09d02fb439eb55bc422e582ac115615b"
"Rev": "d7cb66526fffc811d602b6770581064f4b66b507"
},
{
"ImportPath": "github.com/coreos/go-oidc/oidc",
"Rev": "024cdeee09d02fb439eb55bc422e582ac115615b"
"Rev": "d7cb66526fffc811d602b6770581064f4b66b507"
},
{
"ImportPath": "github.com/coreos/go-semver/semver",
......
package http
import (
"io/ioutil"
"net/http"
"net/http/httptest"
)
import "net/http"
type Client interface {
Do(*http.Request) (*http.Response, error)
}
type HandlerClient struct {
Handler http.Handler
}
func (hc *HandlerClient) Do(r *http.Request) (*http.Response, error) {
w := httptest.NewRecorder()
hc.Handler.ServeHTTP(w, r)
resp := http.Response{
StatusCode: w.Code,
Header: w.Header(),
Body: ioutil.NopCloser(w.Body),
}
return &resp, nil
}
type RequestRecorder struct {
Response *http.Response
Error error
Request *http.Request
}
func (rr *RequestRecorder) Do(req *http.Request) (*http.Response, error) {
rr.Request = req
if rr.Response == nil && rr.Error == nil {
panic("RequestRecorder Response and Error cannot both be nil")
} else if rr.Response != nil && rr.Error != nil {
panic("RequestRecorder Response and Error cannot both be non-nil")
}
return rr.Response, rr.Error
}
func (rr *RequestRecorder) RoundTrip(req *http.Request) (*http.Response, error) {
return rr.Do(req)
}
......@@ -3,6 +3,7 @@ package jose
import (
"encoding/json"
"fmt"
"math"
"time"
)
......@@ -70,13 +71,33 @@ func (c Claims) Int64Claim(name string) (int64, bool, error) {
return v, true, nil
}
func (c Claims) Float64Claim(name string) (float64, bool, error) {
cl, ok := c[name]
if !ok {
return 0, false, nil
}
v, ok := cl.(float64)
if !ok {
vi, ok := cl.(int64)
if !ok {
return 0, false, fmt.Errorf("unable to parse claim as float64: %v", name)
}
v = float64(vi)
}
return v, true, nil
}
func (c Claims) TimeClaim(name string) (time.Time, bool, error) {
v, ok, err := c.Int64Claim(name)
v, ok, err := c.Float64Claim(name)
if !ok || err != nil {
return time.Time{}, ok, err
}
return time.Unix(v, 0).UTC(), true, nil
s := math.Trunc(v)
ns := (v - s) * math.Pow(10, 9)
return time.Unix(int64(s), int64(ns)).UTC(), true, nil
}
func decodeClaims(payload []byte) (Claims, error) {
......
......@@ -13,6 +13,57 @@ const (
HeaderKeyID = "kid"
)
const (
// Encryption Algorithm Header Parameter Values for JWS
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-6
AlgHS256 = "HS256"
AlgHS384 = "HS384"
AlgHS512 = "HS512"
AlgRS256 = "RS256"
AlgRS384 = "RS384"
AlgRS512 = "RS512"
AlgES256 = "ES256"
AlgES384 = "ES384"
AlgES512 = "ES512"
AlgPS256 = "PS256"
AlgPS384 = "PS384"
AlgPS512 = "PS512"
AlgNone = "none"
)
const (
// Algorithm Header Parameter Values for JWE
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-4.1
AlgRSA15 = "RSA1_5"
AlgRSAOAEP = "RSA-OAEP"
AlgRSAOAEP256 = "RSA-OAEP-256"
AlgA128KW = "A128KW"
AlgA192KW = "A192KW"
AlgA256KW = "A256KW"
AlgDir = "dir"
AlgECDHES = "ECDH-ES"
AlgECDHESA128KW = "ECDH-ES+A128KW"
AlgECDHESA192KW = "ECDH-ES+A192KW"
AlgECDHESA256KW = "ECDH-ES+A256KW"
AlgA128GCMKW = "A128GCMKW"
AlgA192GCMKW = "A192GCMKW"
AlgA256GCMKW = "A256GCMKW"
AlgPBES2HS256A128KW = "PBES2-HS256+A128KW"
AlgPBES2HS384A192KW = "PBES2-HS384+A192KW"
AlgPBES2HS512A256KW = "PBES2-HS512+A256KW"
)
const (
// Encryption Algorithm Header Parameter Values for JWE
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-22
EncA128CBCHS256 = "A128CBC-HS256"
EncA128CBCHS384 = "A128CBC-HS384"
EncA256CBCHS512 = "A256CBC-HS512"
EncA128GCM = "A128GCM"
EncA192GCM = "A192GCM"
EncA256GCM = "A256GCM"
)
type JOSEHeader map[string]string
func (j JOSEHeader) Validate() error {
......
......@@ -70,6 +70,10 @@ func (j *JWK) UnmarshalJSON(data []byte) error {
return nil
}
type JWKSet struct {
Keys []JWK `json:"keys"`
}
func decodeExponent(e string) (int, error) {
decE, err := decodeBase64URLPaddingOptional(e)
if err != nil {
......
......@@ -135,7 +135,7 @@ func (s *PrivateKeySet) Active() *PrivateKey {
type GeneratePrivateKeyFunc func() (*PrivateKey, error)
func GeneratePrivateKey() (*PrivateKey, error) {
pk, err := rsa.GenerateKey(rand.Reader, 1024)
pk, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
......
package key
import "errors"
import (
"errors"
"sync"
)
var ErrorNoKeys = errors.New("no keys found")
......@@ -22,6 +25,7 @@ func NewPrivateKeySetRepo() PrivateKeySetRepo {
}
type memPrivateKeySetRepo struct {
mu sync.RWMutex
pks PrivateKeySet
}
......@@ -33,11 +37,17 @@ func (r *memPrivateKeySetRepo) Set(ks KeySet) error {
return errors.New("nil KeySet")
}
r.mu.Lock()
defer r.mu.Unlock()
r.pks = *pks
return nil
}
func (r *memPrivateKeySetRepo) Get() (KeySet, error) {
r.mu.RLock()
defer r.mu.RUnlock()
if r.pks.keys == nil {
return nil, ErrorNoKeys
}
......
......@@ -29,7 +29,7 @@ func (s *KeySetSyncer) Run() chan struct{} {
var failing bool
var next time.Duration
for {
exp, err := sync(s.readable, s.writable, s.clock)
exp, err := syncKeySet(s.readable, s.writable, s.clock)
if err != nil || exp == 0 {
if !failing {
failing = true
......@@ -62,12 +62,12 @@ func (s *KeySetSyncer) Run() chan struct{} {
}
func Sync(r ReadableKeySetRepo, w WritableKeySetRepo) (time.Duration, error) {
return sync(r, w, clockwork.NewRealClock())
return syncKeySet(r, w, clockwork.NewRealClock())
}
// sync copies the keyset from r to the KeySet at w and returns the duration in which the KeySet will expire.
// syncKeySet copies the keyset from r to the KeySet at w and returns the duration in which the KeySet will expire.
// If keyset has already expired, returns a zero duration.
func sync(r ReadableKeySetRepo, w WritableKeySetRepo, clock clockwork.Clock) (exp time.Duration, err error) {
func syncKeySet(r ReadableKeySetRepo, w WritableKeySetRepo, clock clockwork.Clock) (exp time.Duration, err error) {
var ks KeySet
ks, err = r.Get()
if err != nil {
......
......@@ -8,14 +8,49 @@ import (
"mime"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
phttp "github.com/coreos/go-oidc/http"
)
// ResponseTypesEqual compares two response_type values. If either
// contains a space, it is treated as an unordered list. For example,
// comparing "code id_token" and "id_token code" would evaluate to true.
func ResponseTypesEqual(r1, r2 string) bool {
if !strings.Contains(r1, " ") || !strings.Contains(r2, " ") {
// fast route, no split needed
return r1 == r2
}
// split, sort, and compare
r1Fields := strings.Fields(r1)
r2Fields := strings.Fields(r2)
if len(r1Fields) != len(r2Fields) {
return false
}
sort.Strings(r1Fields)
sort.Strings(r2Fields)
for i, r1Field := range r1Fields {
if r1Field != r2Fields[i] {
return false
}
}
return true
}
const (
ResponseTypeCode = "code"
// OAuth2.0 response types registered by OIDC.
//
// See: https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#RegistryContents
ResponseTypeCode = "code"
ResponseTypeCodeIDToken = "code id_token"
ResponseTypeCodeIDTokenToken = "code id_token token"
ResponseTypeIDToken = "id_token"
ResponseTypeIDTokenToken = "id_token token"
ResponseTypeToken = "token"
ResponseTypeNone = "none"
)
const (
......@@ -136,22 +171,24 @@ func (c *Client) commonURLValues() url.Values {
}
}
func (c *Client) newAuthenticatedRequest(url string, values url.Values) (*http.Request, error) {
func (c *Client) newAuthenticatedRequest(urlToken string, values url.Values) (*http.Request, error) {
var req *http.Request
var err error
switch c.authMethod {
case AuthMethodClientSecretPost:
values.Set("client_secret", c.creds.Secret)
req, err = http.NewRequest("POST", url, strings.NewReader(values.Encode()))
req, err = http.NewRequest("POST", urlToken, strings.NewReader(values.Encode()))
if err != nil {
return nil, err
}
case AuthMethodClientSecretBasic:
req, err = http.NewRequest("POST", url, strings.NewReader(values.Encode()))
req, err = http.NewRequest("POST", urlToken, strings.NewReader(values.Encode()))
if err != nil {
return nil, err
}
req.SetBasicAuth(c.creds.ID, c.creds.Secret)
encodedID := url.QueryEscape(c.creds.ID)
encodedSecret := url.QueryEscape(c.creds.Secret)
req.SetBasicAuth(encodedID, encodedSecret)
default:
panic("misconfigured client: auth method not supported")
}
......
......@@ -59,8 +59,8 @@ func NewClaims(iss, sub string, aud interface{}, iat, exp time.Time) jose.Claims
"iss": iss,
"sub": sub,
"aud": aud,
"iat": float64(iat.Unix()),
"exp": float64(exp.Unix()),
"iat": iat.Unix(),
"exp": exp.Unix(),
}
}
......
......@@ -99,10 +99,6 @@ func New(issuerURL, clientID, caFile, usernameClaim, groupsClaim string) (*OIDCA
glog.Infof("Fetched provider config from %s: %#v", issuerURL, cfg)
if cfg.KeysEndpoint == "" {
return nil, fmt.Errorf("OIDC provider must provide 'jwks_uri' for public key discovery")
}
ccfg := oidc.ClientConfig{
HTTPClient: hc,
Credentials: oidc.ClientCredentials{ID: clientID},
......
......@@ -31,6 +31,7 @@ import (
"net"
"net/http"
"net/http/httptest"
"net/url"
"os"
"path"
"path/filepath"
......@@ -70,8 +71,16 @@ func newOIDCProvider(t *testing.T) *oidcProvider {
}
func mustParseURL(t *testing.T, s string) *url.URL {
u, err := url.Parse(s)
if err != nil {
t.Fatalf("Failed to parse url: %v", err)
}
return u
}
func (op *oidcProvider) handleConfig(w http.ResponseWriter, req *http.Request) {
b, err := json.Marshal(op.pcfg)
b, err := json.Marshal(&op.pcfg)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
......@@ -203,7 +212,7 @@ func TestOIDCDiscoveryTimeout(t *testing.T) {
func TestOIDCDiscoveryNoKeyEndpoint(t *testing.T) {
var err error
expectErr := fmt.Errorf("OIDC provider must provide 'jwks_uri' for public key discovery")
expectErr := fmt.Errorf("failed to fetch provider config after 3 retries")
cert := path.Join(os.TempDir(), "oidc-cert")
key := path.Join(os.TempDir(), "oidc-key")
......@@ -225,7 +234,7 @@ func TestOIDCDiscoveryNoKeyEndpoint(t *testing.T) {
// defer srv.Close()
op.pcfg = oidc.ProviderConfig{
Issuer: srv.URL,
Issuer: mustParseURL(t, srv.URL), // An invalid ProviderConfig. Keys endpoint is required.
}
_, err = New(srv.URL, "client-foo", cert, "sub", "")
......@@ -245,8 +254,8 @@ func TestOIDCDiscoverySecureConnection(t *testing.T) {
// defer srv.Close()
op.pcfg = oidc.ProviderConfig{
Issuer: srv.URL,
KeysEndpoint: srv.URL + "/keys",
Issuer: mustParseURL(t, srv.URL),
KeysEndpoint: mustParseURL(t, srv.URL+"/keys"),
}
expectErr := fmt.Errorf("'oidc-issuer-url' (%q) has invalid scheme (%q), require 'https'", srv.URL, "http")
......@@ -282,8 +291,8 @@ func TestOIDCDiscoverySecureConnection(t *testing.T) {
// defer tlsSrv.Close()
op.pcfg = oidc.ProviderConfig{
Issuer: tlsSrv.URL,
KeysEndpoint: tlsSrv.URL + "/keys",
Issuer: mustParseURL(t, tlsSrv.URL),
KeysEndpoint: mustParseURL(t, tlsSrv.URL+"/keys"),
}
// Create a client using cert2, should fail.
......@@ -317,9 +326,15 @@ func TestOIDCAuthentication(t *testing.T) {
// TODO: Uncomment when fix #19254
// defer srv.Close()
// A provider config with all required fields.
op.pcfg = oidc.ProviderConfig{
Issuer: srv.URL,
KeysEndpoint: srv.URL + "/keys",
Issuer: mustParseURL(t, srv.URL),
AuthEndpoint: mustParseURL(t, srv.URL+"/auth"),
TokenEndpoint: mustParseURL(t, srv.URL+"/token"),
KeysEndpoint: mustParseURL(t, srv.URL+"/keys"),
ResponseTypesSupported: []string{"code"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValues: []string{"RS256"},
}
tests := []struct {
......@@ -371,7 +386,7 @@ func TestOIDCAuthentication(t *testing.T) {
op.generateMalformedToken(t, srv.URL, "client-foo", "client-foo", "sub", "user-foo", "", nil),
nil,
false,
"malformed JWS, unable to decode signature",
"oidc: unable to verify JWT signature: no matching keys",
},
{
// Invalid 'aud'.
......@@ -404,7 +419,8 @@ func TestOIDCAuthentication(t *testing.T) {
for i, tt := range tests {
client, err := New(srv.URL, "client-foo", cert, tt.userClaim, tt.groupsClaim)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
t.Errorf("Unexpected error: %v", err)
continue
}
user, result, err := client.AuthenticateToken(tt.token)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment