Fix cannot change user status to disabled

This commit is contained in:
hongming
2022-03-01 11:36:17 +08:00
parent 970780993e
commit 4457f61a22
7 changed files with 38 additions and 38 deletions

View File

@@ -231,7 +231,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
r.Recorder.Event(user, corev1.EventTypeNormal, successSynced, messageResourceSynced) r.Recorder.Event(user, corev1.EventTypeNormal, successSynced, messageResourceSynced)
// block user for AuthenticateRateLimiterDuration duration, after that put it back to the queue to unblock // block user for AuthenticateRateLimiterDuration duration, after that put it back to the queue to unblock
if user.Status.State != nil && *user.Status.State == iamv1alpha2.UserAuthLimitExceeded { if user.Status.State == iamv1alpha2.UserAuthLimitExceeded {
return ctrl.Result{Requeue: true, RequeueAfter: r.AuthenticationOptions.AuthenticateRateLimiterDuration}, nil return ctrl.Result{Requeue: true, RequeueAfter: r.AuthenticationOptions.AuthenticateRateLimiterDuration}, nil
} }
@@ -454,13 +454,17 @@ func (r *Reconciler) deleteLoginRecords(ctx context.Context, user *iamv1alpha2.U
// syncUserStatus Update the user status // syncUserStatus Update the user status
func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User) error { func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User) error {
// skip status sync if the user is disabled
if user.Status.State == iamv1alpha2.UserDisabled {
return nil
}
if user.Spec.EncryptedPassword == "" { if user.Spec.EncryptedPassword == "" {
if user.Labels[iamv1alpha2.IdentifyProviderLabel] != "" { if user.Labels[iamv1alpha2.IdentifyProviderLabel] != "" {
// mapped user from other identity provider always active until disabled // mapped user from other identity provider always active until disabled
if user.Status.State == nil || *user.Status.State != iamv1alpha2.UserActive { if user.Status.State != iamv1alpha2.UserActive {
active := iamv1alpha2.UserActive
user.Status = iamv1alpha2.UserStatus{ user.Status = iamv1alpha2.UserStatus{
State: &active, State: iamv1alpha2.UserActive,
LastTransitionTime: &metav1.Time{Time: time.Now()}, LastTransitionTime: &metav1.Time{Time: time.Now()},
} }
err := r.Update(ctx, user, &client.UpdateOptions{}) err := r.Update(ctx, user, &client.UpdateOptions{})
@@ -469,11 +473,10 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
} }
} }
} else { } else {
// becomes disabled after setting a blank password // empty password is not allowed for normal user
if user.Status.State == nil || *user.Status.State != iamv1alpha2.UserDisabled { if user.Status.State != iamv1alpha2.UserDisabled {
disabled := iamv1alpha2.UserDisabled
user.Status = iamv1alpha2.UserStatus{ user.Status = iamv1alpha2.UserStatus{
State: &disabled, State: iamv1alpha2.UserDisabled,
LastTransitionTime: &metav1.Time{Time: time.Now()}, LastTransitionTime: &metav1.Time{Time: time.Now()},
} }
err := r.Update(ctx, user, &client.UpdateOptions{}) err := r.Update(ctx, user, &client.UpdateOptions{})
@@ -482,32 +485,29 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
} }
} }
} }
// skip auth limit check
return nil return nil
} }
// becomes active after password encrypted // becomes active after password encrypted
if isEncrypted(user.Spec.EncryptedPassword) { if user.Status.State == "" && isEncrypted(user.Spec.EncryptedPassword) {
if user.Status.State == nil || *user.Status.State == iamv1alpha2.UserDisabled { user.Status = iamv1alpha2.UserStatus{
active := iamv1alpha2.UserActive State: iamv1alpha2.UserActive,
user.Status = iamv1alpha2.UserStatus{ LastTransitionTime: &metav1.Time{Time: time.Now()},
State: &active, }
LastTransitionTime: &metav1.Time{Time: time.Now()}, err := r.Update(ctx, user, &client.UpdateOptions{})
} if err != nil {
err := r.Update(ctx, user, &client.UpdateOptions{}) return err
if err != nil {
return err
}
} }
} }
// blocked user, check if need to unblock user // blocked user, check if need to unblock user
if user.Status.State != nil && *user.Status.State == iamv1alpha2.UserAuthLimitExceeded { if user.Status.State == iamv1alpha2.UserAuthLimitExceeded {
if user.Status.LastTransitionTime != nil && if user.Status.LastTransitionTime != nil &&
user.Status.LastTransitionTime.Add(r.AuthenticationOptions.AuthenticateRateLimiterDuration).Before(time.Now()) { user.Status.LastTransitionTime.Add(r.AuthenticationOptions.AuthenticateRateLimiterDuration).Before(time.Now()) {
// unblock user // unblock user
active := iamv1alpha2.UserActive
user.Status = iamv1alpha2.UserStatus{ user.Status = iamv1alpha2.UserStatus{
State: &active, State: iamv1alpha2.UserActive,
LastTransitionTime: &metav1.Time{Time: time.Now()}, LastTransitionTime: &metav1.Time{Time: time.Now()},
} }
err := r.Update(ctx, user, &client.UpdateOptions{}) err := r.Update(ctx, user, &client.UpdateOptions{})
@@ -538,9 +538,8 @@ func (r *Reconciler) syncUserStatus(ctx context.Context, user *iamv1alpha2.User)
// block user if failed login attempts exceeds maximum tries setting // block user if failed login attempts exceeds maximum tries setting
if failedLoginAttempts >= r.AuthenticationOptions.AuthenticateRateLimiterMaxTries { if failedLoginAttempts >= r.AuthenticationOptions.AuthenticateRateLimiterMaxTries {
limitExceed := iamv1alpha2.UserAuthLimitExceeded
user.Status = iamv1alpha2.UserStatus{ user.Status = iamv1alpha2.UserStatus{
State: &limitExceed, State: iamv1alpha2.UserAuthLimitExceeded,
Reason: fmt.Sprintf("Failed login attempts exceed %d in last %s", failedLoginAttempts, r.AuthenticationOptions.AuthenticateRateLimiterDuration), Reason: fmt.Sprintf("Failed login attempts exceed %d in last %s", failedLoginAttempts, r.AuthenticationOptions.AuthenticateRateLimiterDuration),
LastTransitionTime: &metav1.Time{Time: time.Now()}, LastTransitionTime: &metav1.Time{Time: time.Now()},
} }

View File

@@ -125,12 +125,12 @@ func TestDoNothing(t *testing.T) {
// becomes active after password encrypted // becomes active after password encrypted
updateEvent = <-w.ResultChan() updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User) user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, iamv1alpha2.UserActive, *user.Status.State) assert.Equal(t, iamv1alpha2.UserActive, user.Status.State)
// block user // block user
updateEvent = <-w.ResultChan() updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User) user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, iamv1alpha2.UserAuthLimitExceeded, *user.Status.State) assert.Equal(t, iamv1alpha2.UserAuthLimitExceeded, user.Status.State)
assert.True(t, result.Requeue) assert.True(t, result.Requeue)
time.Sleep(result.RequeueAfter + time.Second) time.Sleep(result.RequeueAfter + time.Second)
@@ -144,5 +144,5 @@ func TestDoNothing(t *testing.T) {
// unblock user // unblock user
updateEvent = <-w.ResultChan() updateEvent = <-w.ResultChan()
user = updateEvent.Object.(*iamv1alpha2.User) user = updateEvent.Object.(*iamv1alpha2.User)
assert.Equal(t, iamv1alpha2.UserActive, *user.Status.State) assert.Equal(t, iamv1alpha2.UserActive, user.Status.State)
} }

View File

@@ -112,8 +112,8 @@ func (p *passwordAuthenticator) Authenticate(_ context.Context, username, passwo
} }
// check user status // check user status
if user != nil && (user.Status.State == nil || *user.Status.State != iamv1alpha2.UserActive) { if user != nil && user.Status.State != iamv1alpha2.UserActive {
if user.Status.State != nil && *user.Status.State == iamv1alpha2.UserAuthLimitExceeded { if user.Status.State == iamv1alpha2.UserAuthLimitExceeded {
klog.Errorf("%s, username: %s", RateLimitExceededError, username) klog.Errorf("%s, username: %s", RateLimitExceededError, username)
return nil, "", RateLimitExceededError return nil, "", RateLimitExceededError
} else { } else {

View File

@@ -242,7 +242,6 @@ func newActiveUser(username string, password string) *iamv1alpha2.User {
u := newUser(username, "", "") u := newUser(username, "", "")
password, _ = encrypt(password) password, _ = encrypt(password)
u.Spec.EncryptedPassword = password u.Spec.EncryptedPassword = password
s := iamv1alpha2.UserActive u.Status.State = iamv1alpha2.UserActive
u.Status.State = &s
return u return u
} }

View File

@@ -18,6 +18,7 @@ package im
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"kubesphere.io/kubesphere/pkg/apiserver/authentication" "kubesphere.io/kubesphere/pkg/apiserver/authentication"
@@ -70,7 +71,13 @@ func (im *imOperator) UpdateUser(new *iamv1alpha2.User) (*iamv1alpha2.User, erro
} }
// keep encrypted password and user status // keep encrypted password and user status
new.Spec.EncryptedPassword = old.Spec.EncryptedPassword new.Spec.EncryptedPassword = old.Spec.EncryptedPassword
new.Status = old.Status status := old.Status
// only support enable or disable
if new.Status.State == iamv1alpha2.UserDisabled || new.Status.State == iamv1alpha2.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{}) updated, err := im.ksClient.IamV1alpha2().Users().Update(context.Background(), new, metav1.UpdateOptions{})
if err != nil { if err != nil {
klog.Error(err) klog.Error(err)

View File

@@ -164,7 +164,7 @@ const (
type UserStatus struct { type UserStatus struct {
// The user status // The user status
// +optional // +optional
State *UserState `json:"state,omitempty"` State UserState `json:"state,omitempty"`
// +optional // +optional
Reason string `json:"reason,omitempty"` Reason string `json:"reason,omitempty"`
// +optional // +optional

View File

@@ -770,11 +770,6 @@ func (in *UserSpec) DeepCopy() *UserSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UserStatus) DeepCopyInto(out *UserStatus) { func (in *UserStatus) DeepCopyInto(out *UserStatus) {
*out = *in *out = *in
if in.State != nil {
in, out := &in.State, &out.State
*out = new(UserState)
**out = **in
}
if in.LastTransitionTime != nil { if in.LastTransitionTime != nil {
in, out := &in.LastTransitionTime, &out.LastTransitionTime in, out := &in.LastTransitionTime, &out.LastTransitionTime
*out = (*in).DeepCopy() *out = (*in).DeepCopy()