Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/text v0.3.4
gopkg.in/ldap.v2 v2.5.1
gopkg.in/square/go-jose.v2 v2.2.2
k8s.io/api v0.21.0
k8s.io/apimachinery v0.21.0
k8s.io/apiserver v0.21.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
Expand Down
4 changes: 3 additions & 1 deletion pkg/oauth/registry/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
kubefake "k8s.io/client-go/kubernetes/fake"

oauthv1 "github.com/openshift/api/oauth/v1"
oauthfake "github.com/openshift/client-go/oauth/clientset/versioned/fake"
Expand Down Expand Up @@ -281,7 +282,8 @@ func TestRegistryAndServer(t *testing.T) {
objs = append(objs, testCase.ClientAuth)
}
fakeOAuthClient := oauthfake.NewSimpleClientset(objs...)
storage := registrystorage.New(fakeOAuthClient.OauthV1().OAuthAccessTokens(), fakeOAuthClient.OauthV1().OAuthAuthorizeTokens(), fakeOAuthClient.OauthV1().OAuthClients(), 0)
fakeTokenReviewClient := kubefake.NewSimpleClientset()
storage := registrystorage.New(fakeOAuthClient.OauthV1().OAuthAccessTokens(), fakeOAuthClient.OauthV1().OAuthAuthorizeTokens(), fakeOAuthClient.OauthV1().OAuthClients(), fakeTokenReviewClient.AuthenticationV1().TokenReviews(), 0)
config := osinserver.NewDefaultServerConfig()

h.AuthorizeHandler = osinserver.AuthorizeHandlers{
Expand Down
2 changes: 1 addition & 1 deletion pkg/oauthserver/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (c *OAuthServerConfig) WithOAuth(handler http.Handler) (http.Handler, error
if timeout := c.ExtraOAuthConfig.Options.TokenConfig.AccessTokenInactivityTimeout; timeout != nil {
tokentimeout = int32(timeout.Seconds())
}
storage := registrystorage.New(c.ExtraOAuthConfig.OAuthAccessTokenClient, c.ExtraOAuthConfig.OAuthAuthorizeTokenClient, combinedOAuthClientGetter, tokentimeout)
storage := registrystorage.New(c.ExtraOAuthConfig.OAuthAccessTokenClient, c.ExtraOAuthConfig.OAuthAuthorizeTokenClient, combinedOAuthClientGetter, c.ExtraOAuthConfig.TokenReviewClient, tokentimeout)
config := osinserver.NewDefaultServerConfig()
if authorizationExpiration := c.ExtraOAuthConfig.Options.TokenConfig.AuthorizeTokenMaxAgeSeconds; authorizationExpiration > 0 {
config.AuthorizationExpiration = authorizationExpiration
Expand Down
3 changes: 3 additions & 0 deletions pkg/oauthserver/oauth_apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"k8s.io/apimachinery/pkg/util/yaml"
genericapiserver "k8s.io/apiserver/pkg/server"
kclientset "k8s.io/client-go/kubernetes"
authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1"
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"

Expand Down Expand Up @@ -153,6 +154,7 @@ func NewOAuthServerConfig(oauthConfig osinv1.OAuthConfig, userClientConfig *rest
OAuthClientAuthorizationClient: oauthClient.OAuthClientAuthorizations(),
SessionAuth: sessionAuth,
BootstrapUserDataGetter: bootstrapUserDataGetter,
TokenReviewClient: kubeClient.AuthenticationV1().TokenReviews(),
},
}
genericConfig.BuildHandlerChainFunc = ret.buildHandlerChainForOAuth
Expand Down Expand Up @@ -250,6 +252,7 @@ type ExtraOAuthConfig struct {
SessionAuth session.SessionAuthenticator

BootstrapUserDataGetter bootstrap.BootstrapUserDataGetter
TokenReviewClient authenticationv1client.TokenReviewInterface
}

type OAuthServerConfig struct {
Expand Down
51 changes: 45 additions & 6 deletions pkg/osinserver/registrystorage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import (
"strings"

"github.com/RangelReale/osin"
"gopkg.in/square/go-jose.v2/jwt"

tokenreviewv1 "k8s.io/api/authentication/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/authentication/authenticator"
kuser "k8s.io/apiserver/pkg/authentication/user"
authenticationv1client "k8s.io/client-go/kubernetes/typed/authentication/v1"
"k8s.io/klog/v2"

oauthapi "github.com/openshift/api/oauth/v1"
Expand All @@ -26,22 +30,25 @@ import (
type storage struct {
accesstoken oauthclient.OAuthAccessTokenInterface
authorizetoken oauthclient.OAuthAuthorizeTokenInterface
tokenReview authenticationv1client.TokenReviewInterface
client api.OAuthClientGetter
tokentimeout int32
}

func New(access oauthclient.OAuthAccessTokenInterface, authorize oauthclient.OAuthAuthorizeTokenInterface, client api.OAuthClientGetter, tokentimeout int32) osin.Storage {
func New(access oauthclient.OAuthAccessTokenInterface, authorize oauthclient.OAuthAuthorizeTokenInterface, client api.OAuthClientGetter, tokenReview authenticationv1client.TokenReviewInterface, tokentimeout int32) osin.Storage {
return &storage{
accesstoken: access,
authorizetoken: authorize,
client: client,
tokentimeout: tokentimeout,
tokenReview: tokenReview,
}
}

type clientWrapper struct {
id string
client *oauthapi.OAuthClient
id string
client *oauthapi.OAuthClient
reviewToken func(ctx context.Context, token string, audiences []string) (*tokenreviewv1.TokenReview, error)
}

// Ensure we implement the secret matcher method that allows us to validate multiple secrets
Expand Down Expand Up @@ -70,6 +77,32 @@ func (w *clientWrapper) ClientSecretMatches(secret string) bool {
}
}

// assume this is an SA token
tok, err := jwt.ParseSigned(secret)
if err != nil {
return false
}

if tok != nil {
public := &jwt.Claims{}
err := tok.UnsafeClaimsWithoutVerification(public)
if err != nil {
klog.V(4).Infof("failed to get unsafe claims: %v", err)
return false
}
tokenAuds := authenticator.Audiences(public.Audience)
tokenReview, err := w.reviewToken(context.TODO(), secret, tokenAuds)
if err != nil {
klog.V(4).Infof("the tokenreview failed: %v", err)
return false
}

if tokenReview.Status.User.Username != w.client.Name {
return false
}
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow-up nit:

if tok == nil {
  return false
}

public := &jwt.Claims{}
...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unindent the if-block)


return false
}

Expand Down Expand Up @@ -113,7 +146,13 @@ func (s *storage) GetClient(id string) (osin.Client, error) {
}
return nil, err
}
return &clientWrapper{id, c}, nil
return &clientWrapper{id, c, newTokenReviewer(s.tokenReview)}, nil
}

func newTokenReviewer(tokenReviewer authenticationv1client.TokenReviewInterface) func(ctx context.Context, token string, audiences []string) (*tokenreviewv1.TokenReview, error) {
return func(ctx context.Context, token string, audiences []string) (*tokenreviewv1.TokenReview, error) {
return tokenReviewer.Create(ctx, &tokenreviewv1.TokenReview{Spec: tokenreviewv1.TokenReviewSpec{Token: token, Audiences: audiences}}, metav1.CreateOptions{})
}
}

// SaveAuthorize saves authorize data.
Expand Down Expand Up @@ -226,7 +265,7 @@ func (s *storage) convertFromAuthorizeToken(code string, authorize *oauthapi.OAu
Code: code,
CodeChallenge: authorize.CodeChallenge,
CodeChallengeMethod: authorize.CodeChallengeMethod,
Client: &clientWrapper{authorize.ClientName, client},
Client: &clientWrapper{authorize.ClientName, client, newTokenReviewer(s.tokenReview)},
ExpiresIn: int32(authorize.ExpiresIn),
Scope: scopecovers.Join(authorize.Scopes),
RedirectUri: authorize.RedirectURI,
Expand Down Expand Up @@ -284,7 +323,7 @@ func (s *storage) convertFromAccessToken(code string, access *oauthapi.OAuthAcce
return &osin.AccessData{
AccessToken: code,
RefreshToken: access.RefreshToken,
Client: &clientWrapper{access.ClientName, client},
Client: &clientWrapper{access.ClientName, client, newTokenReviewer(s.tokenReview)},
ExpiresIn: int32(access.ExpiresIn),
Scope: scopecovers.Join(access.Scopes),
RedirectUri: access.RedirectURI,
Expand Down
Loading