diff options
Diffstat (limited to 'kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg')
4 files changed, 401 insertions, 0 deletions
diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/gcp/gcp.go b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/gcp/gcp.go new file mode 100644 index 0000000..32cbb36 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/gcp/gcp.go @@ -0,0 +1,106 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package gcp + +import ( + "net/http" + "time" + + "github.com/golang/glog" + "golang.org/x/net/context" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + + "k8s.io/kubernetes/pkg/client/restclient" +) + +func init() { + if err := restclient.RegisterAuthProviderPlugin("gcp", newGCPAuthProvider); err != nil { + glog.Fatalf("Failed to register gcp auth plugin: %v", err) + } +} + +type gcpAuthProvider struct { + tokenSource oauth2.TokenSource + persister restclient.AuthProviderConfigPersister +} + +func newGCPAuthProvider(_ string, gcpConfig map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) { + ts, err := newCachedTokenSource(gcpConfig["access-token"], gcpConfig["expiry"], persister) + if err != nil { + return nil, err + } + return &gcpAuthProvider{ts, persister}, nil +} + +func (g *gcpAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper { + return &oauth2.Transport{ + Source: g.tokenSource, + Base: rt, + } +} + +func (g *gcpAuthProvider) Login() error { return nil } + +type cachedTokenSource struct { + source oauth2.TokenSource + accessToken string + expiry time.Time + persister restclient.AuthProviderConfigPersister +} + +func newCachedTokenSource(accessToken, expiry string, persister restclient.AuthProviderConfigPersister) (*cachedTokenSource, error) { + var expiryTime time.Time + if parsedTime, err := time.Parse(time.RFC3339Nano, expiry); err == nil { + expiryTime = parsedTime + } + ts, err := google.DefaultTokenSource(context.Background(), "https://www.googleapis.com/auth/cloud-platform") + if err != nil { + return nil, err + } + return &cachedTokenSource{ + source: ts, + accessToken: accessToken, + expiry: expiryTime, + persister: persister, + }, nil +} + +func (t *cachedTokenSource) Token() (*oauth2.Token, error) { + tok := &oauth2.Token{ + AccessToken: t.accessToken, + TokenType: "Bearer", + Expiry: t.expiry, + } + if tok.Valid() && !tok.Expiry.IsZero() { + return tok, nil + } + tok, err := t.source.Token() + if err != nil { + return nil, err + } + if t.persister != nil { + cached := map[string]string{ + "access-token": tok.AccessToken, + "expiry": tok.Expiry.Format(time.RFC3339Nano), + } + if err := t.persister.Persist(cached); err != nil { + glog.V(4).Infof("Failed to persist token: %v", err) + } + } + return tok, nil +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/OWNERS b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/OWNERS new file mode 100644 index 0000000..ecf3349 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/OWNERS @@ -0,0 +1,2 @@ +assignees: + - bobbyrullo diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/oidc.go b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/oidc.go new file mode 100644 index 0000000..690a452 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/oidc/oidc.go @@ -0,0 +1,270 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oidc + +import ( + "encoding/base64" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/coreos/go-oidc/jose" + "github.com/coreos/go-oidc/oauth2" + "github.com/coreos/go-oidc/oidc" + "github.com/golang/glog" + + "k8s.io/kubernetes/pkg/client/restclient" + "k8s.io/kubernetes/pkg/util/wait" +) + +const ( + cfgIssuerUrl = "idp-issuer-url" + cfgClientID = "client-id" + cfgClientSecret = "client-secret" + cfgCertificateAuthority = "idp-certificate-authority" + cfgCertificateAuthorityData = "idp-certificate-authority-data" + cfgExtraScopes = "extra-scopes" + cfgIDToken = "id-token" + cfgRefreshToken = "refresh-token" +) + +var ( + backoff = wait.Backoff{ + Duration: 1 * time.Second, + Factor: 2, + Jitter: .1, + Steps: 5, + } +) + +func init() { + if err := restclient.RegisterAuthProviderPlugin("oidc", newOIDCAuthProvider); err != nil { + glog.Fatalf("Failed to register oidc auth plugin: %v", err) + } +} + +func newOIDCAuthProvider(_ string, cfg map[string]string, persister restclient.AuthProviderConfigPersister) (restclient.AuthProvider, error) { + issuer := cfg[cfgIssuerUrl] + if issuer == "" { + return nil, fmt.Errorf("Must provide %s", cfgIssuerUrl) + } + + clientID := cfg[cfgClientID] + if clientID == "" { + return nil, fmt.Errorf("Must provide %s", cfgClientID) + } + + clientSecret := cfg[cfgClientSecret] + if clientSecret == "" { + return nil, fmt.Errorf("Must provide %s", cfgClientSecret) + } + + var certAuthData []byte + var err error + if cfg[cfgCertificateAuthorityData] != "" { + certAuthData, err = base64.StdEncoding.DecodeString(cfg[cfgCertificateAuthorityData]) + if err != nil { + return nil, err + } + } + + clientConfig := restclient.Config{ + TLSClientConfig: restclient.TLSClientConfig{ + CAFile: cfg[cfgCertificateAuthority], + CAData: certAuthData, + }, + } + + trans, err := restclient.TransportFor(&clientConfig) + if err != nil { + return nil, err + } + hc := &http.Client{Transport: trans} + + providerCfg, err := oidc.FetchProviderConfig(hc, strings.TrimSuffix(issuer, "/")) + if err != nil { + return nil, fmt.Errorf("error fetching provider config: %v", err) + } + + scopes := strings.Split(cfg[cfgExtraScopes], ",") + oidcCfg := oidc.ClientConfig{ + HTTPClient: hc, + Credentials: oidc.ClientCredentials{ + ID: clientID, + Secret: clientSecret, + }, + ProviderConfig: providerCfg, + Scope: append(scopes, oidc.DefaultScope...), + } + + client, err := oidc.NewClient(oidcCfg) + if err != nil { + return nil, fmt.Errorf("error creating OIDC Client: %v", err) + } + + oClient := &oidcClient{client} + + var initialIDToken jose.JWT + if cfg[cfgIDToken] != "" { + initialIDToken, err = jose.ParseJWT(cfg[cfgIDToken]) + if err != nil { + return nil, err + } + } + + return &oidcAuthProvider{ + initialIDToken: initialIDToken, + refresher: &idTokenRefresher{ + client: oClient, + cfg: cfg, + persister: persister, + }, + }, nil +} + +type oidcAuthProvider struct { + refresher *idTokenRefresher + initialIDToken jose.JWT +} + +func (g *oidcAuthProvider) WrapTransport(rt http.RoundTripper) http.RoundTripper { + at := &oidc.AuthenticatedTransport{ + TokenRefresher: g.refresher, + RoundTripper: rt, + } + at.SetJWT(g.initialIDToken) + return &roundTripper{ + wrapped: at, + refresher: g.refresher, + } +} + +func (g *oidcAuthProvider) Login() error { + return errors.New("not yet implemented") +} + +type OIDCClient interface { + refreshToken(rt string) (oauth2.TokenResponse, error) + verifyJWT(jwt jose.JWT) error +} + +type roundTripper struct { + refresher *idTokenRefresher + wrapped *oidc.AuthenticatedTransport +} + +func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + var res *http.Response + var err error + firstTime := true + wait.ExponentialBackoff(backoff, func() (bool, error) { + if !firstTime { + var jwt jose.JWT + jwt, err = r.refresher.Refresh() + if err != nil { + return true, nil + } + r.wrapped.SetJWT(jwt) + } else { + firstTime = false + } + + res, err = r.wrapped.RoundTrip(req) + if err != nil { + return true, nil + } + if res.StatusCode == http.StatusUnauthorized { + return false, nil + } + return true, nil + }) + return res, err +} + +type idTokenRefresher struct { + cfg map[string]string + client OIDCClient + persister restclient.AuthProviderConfigPersister + intialIDToken jose.JWT +} + +func (r *idTokenRefresher) Verify(jwt jose.JWT) error { + claims, err := jwt.Claims() + if err != nil { + return err + } + + now := time.Now() + exp, ok, err := claims.TimeClaim("exp") + switch { + case err != nil: + return fmt.Errorf("failed to parse 'exp' claim: %v", err) + case !ok: + return errors.New("missing required 'exp' claim") + case exp.Before(now): + return fmt.Errorf("token already expired at: %v", exp) + } + + return nil +} + +func (r *idTokenRefresher) Refresh() (jose.JWT, error) { + rt, ok := r.cfg[cfgRefreshToken] + if !ok { + return jose.JWT{}, errors.New("No valid id-token, and cannot refresh without refresh-token") + } + + tokens, err := r.client.refreshToken(rt) + if err != nil { + return jose.JWT{}, fmt.Errorf("could not refresh token: %v", err) + } + jwt, err := jose.ParseJWT(tokens.IDToken) + if err != nil { + return jose.JWT{}, err + } + + if tokens.RefreshToken != "" && tokens.RefreshToken != rt { + r.cfg[cfgRefreshToken] = tokens.RefreshToken + } + r.cfg[cfgIDToken] = jwt.Encode() + + err = r.persister.Persist(r.cfg) + if err != nil { + return jose.JWT{}, fmt.Errorf("could not perist new tokens: %v", err) + } + + return jwt, r.client.verifyJWT(jwt) +} + +type oidcClient struct { + client *oidc.Client +} + +func (o *oidcClient) refreshToken(rt string) (oauth2.TokenResponse, error) { + oac, err := o.client.OAuthClient() + if err != nil { + return oauth2.TokenResponse{}, err + } + + return oac.RequestToken(oauth2.GrantTypeRefreshToken, rt) +} + +func (o *oidcClient) verifyJWT(jwt jose.JWT) error { + return o.client.VerifyJWT(jwt) +} diff --git a/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/plugins.go b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/plugins.go new file mode 100644 index 0000000..17d3ad4 --- /dev/null +++ b/kube2msb/src/vendor/k8s.io/kubernetes/plugin/pkg/client/auth/plugins.go @@ -0,0 +1,23 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + // Initialize all known client auth plugins. + _ "k8s.io/kubernetes/plugin/pkg/client/auth/gcp" + _ "k8s.io/kubernetes/plugin/pkg/client/auth/oidc" +) |