feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -1,69 +1,59 @@
/*
Copyright 2020 The KubeSphere Authors.
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
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 im
import (
"context"
"fmt"
"strconv"
"time"
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
iamv1alpha2 "kubesphere.io/api/iam/v1alpha2"
"k8s.io/utils/ptr"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
"kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
"kubesphere.io/kubesphere/pkg/apiserver/query"
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/models/auth"
resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3"
resourcev1beta1 "kubesphere.io/kubesphere/pkg/models/resources/v1beta1"
)
type IdentityManagementInterface interface {
CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
CreateUser(user *iamv1beta1.User) (*iamv1beta1.User, error)
ListUsers(query *query.Query) (*api.ListResult, error)
DeleteUser(username string) error
UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
DescribeUser(username string) (*iamv1alpha2.User, error)
UpdateUser(user *iamv1beta1.User) (*iamv1beta1.User, error)
DescribeUser(username string) (*iamv1beta1.User, error)
ModifyPassword(username string, password string) error
ListLoginRecords(username string, query *query.Query) (*api.ListResult, error)
PasswordVerify(username string, password string) error
}
func NewOperator(ksClient kubesphere.Interface, userGetter resources.Interface, loginRecordGetter resources.Interface, options *authentication.Options) IdentityManagementInterface {
func NewOperator(client runtimeclient.Client, resourceManager resourcev1beta1.ResourceManager, options *authentication.Options) IdentityManagementInterface {
im := &imOperator{
ksClient: ksClient,
userGetter: userGetter,
loginRecordGetter: loginRecordGetter,
options: options,
client: client,
options: options,
resourceManager: resourceManager,
}
return im
}
type imOperator struct {
ksClient kubesphere.Interface
userGetter resources.Interface
loginRecordGetter resources.Interface
options *authentication.Options
client runtimeclient.Client
resourceManager resourcev1beta1.ResourceManager
options *authentication.Options
}
// UpdateUser returns user information after update.
func (im *imOperator) UpdateUser(new *iamv1alpha2.User) (*iamv1alpha2.User, error) {
func (im *imOperator) UpdateUser(new *iamv1beta1.User) (*iamv1beta1.User, error) {
old, err := im.fetch(new.Name)
if err != nil {
klog.Error(err)
@@ -73,109 +63,108 @@ func (im *imOperator) UpdateUser(new *iamv1alpha2.User) (*iamv1alpha2.User, erro
new.Spec.EncryptedPassword = old.Spec.EncryptedPassword
status := old.Status
// only support enable or disable
if new.Status.State == iamv1alpha2.UserDisabled || new.Status.State == iamv1alpha2.UserActive {
if new.Status.State == iamv1beta1.UserDisabled || new.Status.State == iamv1beta1.UserActive {
status.State = new.Status.State
status.LastTransitionTime = &metav1.Time{Time: time.Now()}
}
new.Status = status
updated, err := im.ksClient.IamV1alpha2().Users().Update(context.Background(), new, metav1.UpdateOptions{})
if err != nil {
klog.Error(err)
if err := im.client.Update(context.Background(), new); err != nil {
return nil, err
}
return ensurePasswordNotOutput(updated), nil
new = new.DeepCopy()
new.Spec.EncryptedPassword = ""
return new, nil
}
func (im *imOperator) fetch(username string) (*iamv1alpha2.User, error) {
obj, err := im.userGetter.Get("", username)
if err != nil {
klog.Error(err)
func (im *imOperator) fetch(username string) (*iamv1beta1.User, error) {
user := &iamv1beta1.User{}
if err := im.client.Get(context.Background(), types.NamespacedName{Name: username}, user); err != nil {
return nil, err
}
user := obj.(*iamv1alpha2.User).DeepCopy()
return user, nil
return user.DeepCopy(), nil
}
func (im *imOperator) ModifyPassword(username string, password string) error {
user, err := im.fetch(username)
if err != nil {
klog.Error(err)
return err
}
user.Spec.EncryptedPassword = password
_, err = im.ksClient.IamV1alpha2().Users().Update(context.Background(), user, metav1.UpdateOptions{})
if err != nil {
klog.Error(err)
if err := im.client.Update(context.Background(), user); err != nil {
return err
}
return nil
}
func (im *imOperator) ListUsers(query *query.Query) (result *api.ListResult, err error) {
result, err = im.userGetter.List("", query)
func (im *imOperator) ListUsers(query *query.Query) (*api.ListResult, error) {
result, err := im.resourceManager.ListResources(context.Background(), iamv1beta1.SchemeGroupVersion.WithResource(iamv1beta1.ResourcesPluralUser), "", query)
if err != nil {
klog.Error(err)
return nil, err
}
items := make([]interface{}, 0)
for _, item := range result.Items {
user := item.(*iamv1alpha2.User)
out := ensurePasswordNotOutput(user)
items := make([]runtime.Object, 0)
userList := result.(*iamv1beta1.UserList)
for _, item := range userList.Items {
out := item.DeepCopy()
out.Spec.EncryptedPassword = ""
items = append(items, out)
}
result.Items = items
return result, nil
total, err := strconv.ParseInt(userList.GetContinue(), 10, 64)
if err != nil {
return nil, err
}
return &api.ListResult{Items: items, TotalItems: int(total)}, nil
}
func (im *imOperator) PasswordVerify(username string, password string) error {
obj, err := im.userGetter.Get("", username)
user, err := im.fetch(username)
if err != nil {
klog.Error(err)
return err
}
user := obj.(*iamv1alpha2.User)
if err = auth.PasswordVerify(user.Spec.EncryptedPassword, password); err != nil {
return err
}
return nil
}
func (im *imOperator) DescribeUser(username string) (*iamv1alpha2.User, error) {
obj, err := im.userGetter.Get("", username)
func (im *imOperator) DescribeUser(username string) (*iamv1beta1.User, error) {
user, err := im.fetch(username)
if err != nil {
klog.Error(err)
return nil, err
}
user := obj.(*iamv1alpha2.User)
return ensurePasswordNotOutput(user), nil
out := user.DeepCopy()
out.Spec.EncryptedPassword = ""
return out, nil
}
func (im *imOperator) DeleteUser(username string) error {
return im.ksClient.IamV1alpha2().Users().Delete(context.Background(), username, *metav1.NewDeleteOptions(0))
user, err := im.fetch(username)
if err != nil {
return err
}
return im.client.Delete(context.Background(), user, &runtimeclient.DeleteOptions{GracePeriodSeconds: ptr.To[int64](0)})
}
func (im *imOperator) CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
user, err := im.ksClient.IamV1alpha2().Users().Create(context.Background(), user, metav1.CreateOptions{})
if err != nil {
klog.Error(err)
func (im *imOperator) CreateUser(user *iamv1beta1.User) (*iamv1beta1.User, error) {
if err := im.client.Create(context.Background(), user); err != nil {
return nil, err
}
return user, nil
}
func (im *imOperator) ListLoginRecords(username string, q *query.Query) (*api.ListResult, error) {
q.Filters[query.FieldLabel] = query.Value(fmt.Sprintf("%s=%s", iamv1alpha2.UserReferenceLabel, username))
result, err := im.loginRecordGetter.List("", q)
q.Filters[query.FieldLabel] = query.Value(fmt.Sprintf("%s=%s", iamv1beta1.UserReferenceLabel, username))
result, err := im.resourceManager.ListResources(context.Background(), iamv1beta1.SchemeGroupVersion.WithResource(iamv1beta1.ResourcesPluralLoginRecord), "", q)
if err != nil {
klog.Error(err)
return nil, err
}
return result, nil
}
func ensurePasswordNotOutput(user *iamv1alpha2.User) *iamv1alpha2.User {
out := user.DeepCopy()
// ensure encrypted password will not be output
out.Spec.EncryptedPassword = ""
return out
items := make([]runtime.Object, 0)
userList := result.(*iamv1beta1.LoginRecordList)
for _, item := range userList.Items {
items = append(items, item.DeepCopy())
}
total, err := strconv.ParseInt(userList.GetContinue(), 10, 64)
if err != nil {
return nil, err
}
return &api.ListResult{Items: items, TotalItems: int(total)}, nil
}