Skip to content

Commit

Permalink
list by fieldselector, add get
Browse files Browse the repository at this point in the history
  • Loading branch information
stlaz committed Oct 22, 2020
1 parent fb735ae commit 1e2c154
Showing 1 changed file with 54 additions and 34 deletions.
88 changes: 54 additions & 34 deletions pkg/oauth/apiserver/registry/personaltokens/delegate/delegate.go
Expand Up @@ -8,6 +8,7 @@ import (
kerrors "k8s.io/apimachinery/pkg/api/errors"
metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
Expand All @@ -31,11 +32,12 @@ type REST struct {
}

var _ rest.Lister = &REST{}
var _ rest.Getter = &REST{}
var _ rest.GracefulDeleter = &REST{}
var _ rest.Scoper = &REST{}

// TODO: add watcher?
// var _ rest.Watcher = &REST{}
var _ rest.Scoper = &REST{}

// NewREST returns a RESTStorage object that will work against access tokens
func NewREST(accessTokenGetter oauthv1client.OAuthAccessTokensGetter) (*REST, error) {
Expand All @@ -54,26 +56,48 @@ func (r *REST) NewList() runtime.Object {
}

func (r *REST) List(ctx context.Context, options *metainternal.ListOptions) (runtime.Object, error) {
userInfo, exists := apirequest.UserFrom(ctx)
if !exists {
return nil, kerrors.NewForbidden(oauth.Resource("personaltoken"), "", fmt.Errorf("unable to list personal tokens without a user in context"))
fieldSelector, err := constructUserFieldSelector(ctx)
if err != nil {
return nil, err
}

// FIXME: ignore listoptions for now
tokenList, err := r.accessTokenGetter.OAuthAccessTokens().List(ctx, metav1.ListOptions{})
tokenList, err := r.accessTokenGetter.OAuthAccessTokens().List(ctx, metav1.ListOptions{FieldSelector: fieldSelector.String()})
if err != nil {
return nil, err
}

var internalTokenList oauthapi.OAuthAccessTokenList
if err := oauthapiv1.Convert_v1_OAuthAccessTokenList_To_oauth_OAuthAccessTokenList(tokenList, &internalTokenList, nil); err != nil {
return nil, err
}

return &internalTokenList, nil
}

func (r *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
ctxUserName, err := getUserFromContext(ctx)
if err != nil {
return nil, err
}

personalTokenList, err := filterTokensPerUser(tokenList, userInfo.GetName())
token, err := r.accessTokenGetter.OAuthAccessTokens().Get(ctx, name, *options)
if err != nil {
return nil, kerrors.NewInternalError(err)
return nil, err
}

if token.UserName != ctxUserName { // don't reveal other people tokens' hashes
return nil, errors.NewNotFound(oauth.Resource("personaltoken"), name)
}

return personalTokenList, nil
var internalToken oauthapi.OAuthAccessToken
if err := oauthapiv1.Convert_v1_OAuthAccessToken_To_oauth_OAuthAccessToken(token, &internalToken, nil); err != nil {
return nil, err
}

return &internalToken, nil
}

// FIXME:
func (r *REST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
return r.tableConvertor.ConvertToTable(ctx, object, tableOptions)
}
Expand All @@ -83,40 +107,36 @@ func (r *REST) NamespaceScoped() bool {
}

func (r *REST) Delete(ctx context.Context, name string, _ rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
userInfo, exists := apirequest.UserFrom(ctx)
if !exists {
return &metav1.Status{Status: metav1.StatusFailure}, false, kerrors.NewForbidden(oauth.Resource("personaltoken"), "", fmt.Errorf("unable to list personal tokens without a user in context"))
}

// TODO: what about --all or label/fieldselectors? (e.g. remove all tokens issued to a certain client)
token, err := r.accessTokenGetter.OAuthAccessTokens().Get(ctx, name, metav1.GetOptions{})
if err != nil && errors.IsNotFound(err) {
if _, err := r.Get(ctx, name, &metav1.GetOptions{}); err != nil {
return &metav1.Status{Status: metav1.StatusFailure}, false, err
}

if token.UserName != userInfo.GetName() { // don't reveal other people tokens' hashes
return &metav1.Status{Status: metav1.StatusFailure}, false, errors.NewNotFound(oauth.Resource("personaltoken"), name)
}

var opts metav1.DeleteOptions
if options != nil {
opts = *options
}
return &metav1.Status{Status: metav1.StatusSuccess}, false, r.accessTokenGetter.OAuthAccessTokens().Delete(ctx, name, opts)
}

func filterTokensPerUser(tokens *oauthv1.OAuthAccessTokenList, username string) (*oauthapi.PersonalAccessTokenList, error) {
filtered := []oauthapi.OAuthAccessToken{}
for _, t := range tokens.Items {
if t.UserName == username {
var internalToken oauthapi.OAuthAccessToken
if err := oauthapiv1.Convert_v1_OAuthAccessToken_To_oauth_OAuthAccessToken(&t, &internalToken, nil); err != nil {
return nil, err
}
filtered = append(filtered, internalToken)
}
func constructUserFieldSelector(ctx context.Context) (fields.Selector, error) {
userName, err := getUserFromContext(ctx)
if err != nil {
return nil, err
}
return &oauthapi.PersonalAccessTokenList{
Items: filtered,
}, nil

return fields.Set{"userName": userName}.AsSelector(), nil
}

func getUserFromContext(ctx context.Context) (string, error) {
userInfo, exists := apirequest.UserFrom(ctx)
if !exists {
return "", kerrors.NewForbidden(oauth.Resource("personaltokens"), "", fmt.Errorf("unable to get personal tokens without a user in context"))
}

userName := userInfo.GetName()
if len(userName) == 0 {
return "", kerrors.NewForbidden(oauth.Resource("personaltokens"), "", fmt.Errorf("user has a zero-length username"))
}

return userName, nil
}

0 comments on commit 1e2c154

Please sign in to comment.