Skip to content

Commit

Permalink
feat(auth): limit action of changing user's password (#928)
Browse files Browse the repository at this point in the history
  • Loading branch information
wangao1236 committed Nov 23, 2020
1 parent 5ceb4f2 commit bbf5123
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 14 deletions.
28 changes: 20 additions & 8 deletions pkg/auth/registry/localidentity/storage/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,29 @@ package storage

import (
"context"
"fmt"

"k8s.io/apimachinery/pkg/api/errors"
"tkestack.io/tke/api/auth"
authinternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/auth/internalversion"
"tkestack.io/tke/pkg/apiserver/authentication"
"tkestack.io/tke/pkg/auth/registry/localidentity"
"tkestack.io/tke/pkg/auth/util"
"tkestack.io/tke/pkg/util/log"

"github.com/casbin/casbin/v2"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic/registry"
"k8s.io/apiserver/pkg/registry/rest"

"tkestack.io/tke/api/auth"
authinternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/auth/internalversion"
"tkestack.io/tke/pkg/auth/registry/localidentity"
"tkestack.io/tke/pkg/util/log"
)

// PasswordREST implements the REST endpoint.
type PasswordREST struct {
localIdentityStore *registry.Store
authClient authinternalclient.AuthInterface
enforcer *casbin.SyncedEnforcer
}

var _ = rest.Creater(&PasswordREST{})
Expand All @@ -51,18 +55,26 @@ func (r *PasswordREST) New() runtime.Object {

// Create used to update password of the local identity.
func (r *PasswordREST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
username, tenantID := authentication.UsernameAndTenantID(ctx)
isPlatformAdmin, err := util.IsPlatformAdmin(ctx, username, tenantID, r.authClient, r.enforcer)
if err != nil {
return nil, err
}

requestInfo, ok := request.RequestInfoFrom(ctx)
if !ok {
return nil, errors.NewBadRequest("unable to get request info from context")
return nil, apierrors.NewBadRequest("unable to get request info from context")
}

userID := requestInfo.Name

localIdentityObj, err := r.localIdentityStore.Get(ctx, userID, &metav1.GetOptions{})
if err != nil {
return nil, err
}
localIdentity := localIdentityObj.(*auth.LocalIdentity)
if !isPlatformAdmin && (localIdentity.Spec.Username != username || localIdentity.Spec.TenantID != tenantID) {
return nil, fmt.Errorf("you are not a administrator, and you are not allowd to change other users' password")
}

passwordReq := obj.(*auth.PasswordReq)

Expand Down
15 changes: 13 additions & 2 deletions pkg/auth/registry/localidentity/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func NewStorage(optsGetter generic.RESTOptionsGetter, authClient authinternalcli

return &Storage{
LocalIdentity: &REST{store, authClient, enforcer, privilegedUsername},
Password: &PasswordREST{store, authClient},
Password: &PasswordREST{store, authClient, enforcer},
Status: &StatusREST{&statusStore},
Policy: &PolicyREST{store, authClient, enforcer},
Role: &RoleREST{store, authClient, enforcer},
Expand Down Expand Up @@ -326,11 +326,22 @@ func (r *REST) Export(ctx context.Context, name string, options metav1.ExportOpt
func (r *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
// subresources should never allow create on update.
_, err := ValidateGetObjectAndTenantID(ctx, r.Store, name, &metav1.GetOptions{})
obj, err := ValidateGetObjectAndTenantID(ctx, r.Store, name, &metav1.GetOptions{})
if err != nil {
return nil, false, err
}

username, tenantID := authentication.UsernameAndTenantID(ctx)
isPlatformAdmin, err := util.IsPlatformAdmin(ctx, username, tenantID, r.authClient, r.enforcer)
if err != nil {
return nil, false, err
}

localIdentity := obj.(*auth.LocalIdentity)
if !isPlatformAdmin && (localIdentity.Spec.Username != username || localIdentity.Spec.TenantID != tenantID) {
return nil, false, fmt.Errorf("you are not a administrator, and you are not allowd to change other users")
}

return r.Store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
}

Expand Down
54 changes: 54 additions & 0 deletions pkg/auth/util/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Tencent is pleased to support the open source community by making TKEStack available.
*
* Copyright (C) 2012-2020 Tencent. All Rights Reserved.
*
* 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
*
* https://opensource.org/licenses/Apache-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 OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package util

import (
"context"
"fmt"

"github.com/casbin/casbin/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
authinternalclient "tkestack.io/tke/api/client/clientset/internalversion/typed/auth/internalversion"
)

func IsPlatformAdmin(ctx context.Context, username string, tenantID string, authClient authinternalclient.AuthInterface,
enforcer *casbin.SyncedEnforcer) (bool, error) {
idp, err := authClient.IdentityProviders().Get(ctx, tenantID, metav1.GetOptions{})
if err != nil {
return false, err
}
administrators := idp.Spec.Administrators
for _, admin := range administrators {
if admin == username {
return true, nil
}
}

// Use implicit roles to check admin
roles, err := enforcer.GetImplicitRolesForUser(UserKey(tenantID, username), DefaultDomain)
if err != nil {
return false, err
}
for _, r := range roles {
if r == fmt.Sprintf(AdministratorPolicyPattern, tenantID) {
return true, nil
}
}

return false, nil
}
8 changes: 4 additions & 4 deletions pkg/auth/util/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ const (
PoliciesKey = "policies"
administratorKey = "administrator"

platformPolicyPattern = "pol-%s-platform"
administratorPolicyPattern = "pol-%s-administrator"
PlatformPolicyPattern = "pol-%s-platform"
AdministratorPolicyPattern = "pol-%s-administrator"
)

func GetLocalIdentity(ctx context.Context, authClient authinternalclient.AuthInterface, tenantID, username string) (auth.LocalIdentity, error) {
Expand Down Expand Up @@ -228,8 +228,8 @@ func SetAdministrator(ctx context.Context, enforcer *casbin.SyncedEnforcer, auth
return
}
for _, r := range roles {
if r == fmt.Sprintf(platformPolicyPattern, localIdentity.Spec.TenantID) ||
r == fmt.Sprintf(administratorPolicyPattern, localIdentity.Spec.TenantID) {
if r == fmt.Sprintf(PlatformPolicyPattern, localIdentity.Spec.TenantID) ||
r == fmt.Sprintf(AdministratorPolicyPattern, localIdentity.Spec.TenantID) {
localIdentity.Spec.Extra[administratorKey] = "true"
return
}
Expand Down

0 comments on commit bbf5123

Please sign in to comment.