diff --git a/cmd/controller-manager/app/controllers.go b/cmd/controller-manager/app/controllers.go index 0f125a554..8c6e417ac 100644 --- a/cmd/controller-manager/app/controllers.go +++ b/cmd/controller-manager/app/controllers.go @@ -48,6 +48,7 @@ import ( "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/simple/client/devops" "kubesphere.io/kubesphere/pkg/simple/client/k8s" + ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" "sigs.k8s.io/controller-runtime/pkg/manager" @@ -60,6 +61,7 @@ func addControllers( informerFactory informers.InformerFactory, devopsClient devops.Interface, s3Client s3.Interface, + ldapClient ldapclient.Interface, openpitrixClient openpitrix.Client, multiClusterEnabled bool, networkPolicyEnabled bool, @@ -207,8 +209,8 @@ func addControllers( } userController := user.NewController(client.Kubernetes(), client.KubeSphere(), client.Config(), - kubesphereInformer.Iam().V1alpha2().Users(), - fedUserCache, fedUserCacheController, kubernetesInformer.Core().V1().ConfigMaps(), multiClusterEnabled) + kubesphereInformer.Iam().V1alpha2().Users(), fedUserCache, fedUserCacheController, + kubernetesInformer.Core().V1().ConfigMaps(), ldapClient, multiClusterEnabled) csrController := certificatesigningrequest.NewController(client.Kubernetes(), kubernetesInformer.Certificates().V1beta1().CertificateSigningRequests(), kubernetesInformer.Core().V1().ConfigMaps(), client.Config()) diff --git a/cmd/controller-manager/app/options/options.go b/cmd/controller-manager/app/options/options.go index 4bb1ee157..8b42db8d3 100644 --- a/cmd/controller-manager/app/options/options.go +++ b/cmd/controller-manager/app/options/options.go @@ -8,6 +8,7 @@ import ( "k8s.io/klog" "kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins" "kubesphere.io/kubesphere/pkg/simple/client/k8s" + ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" "kubesphere.io/kubesphere/pkg/simple/client/multicluster" "kubesphere.io/kubesphere/pkg/simple/client/network" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" @@ -21,6 +22,7 @@ type KubeSphereControllerManagerOptions struct { KubernetesOptions *k8s.KubernetesOptions DevopsOptions *jenkins.Options S3Options *s3.Options + LdapOptions *ldapclient.Options OpenPitrixOptions *openpitrix.Options NetworkOptions *network.Options MultiClusterOptions *multicluster.Options @@ -35,6 +37,7 @@ func NewKubeSphereControllerManagerOptions() *KubeSphereControllerManagerOptions KubernetesOptions: k8s.NewKubernetesOptions(), DevopsOptions: jenkins.NewDevopsOptions(), S3Options: s3.NewS3Options(), + LdapOptions: ldapclient.NewOptions(), OpenPitrixOptions: openpitrix.NewOptions(), NetworkOptions: network.NewNetworkOptions(), MultiClusterOptions: multicluster.NewOptions(), @@ -57,6 +60,7 @@ func (s *KubeSphereControllerManagerOptions) Flags() cliflag.NamedFlagSets { s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"), s.KubernetesOptions) s.DevopsOptions.AddFlags(fss.FlagSet("devops"), s.DevopsOptions) s.S3Options.AddFlags(fss.FlagSet("s3"), s.S3Options) + s.LdapOptions.AddFlags(fss.FlagSet("ldap"), s.LdapOptions) s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), s.OpenPitrixOptions) s.NetworkOptions.AddFlags(fss.FlagSet("network"), s.NetworkOptions) s.MultiClusterOptions.AddFlags(fss.FlagSet("multicluster"), s.MultiClusterOptions) @@ -92,6 +96,7 @@ func (s *KubeSphereControllerManagerOptions) Validate() []error { errs = append(errs, s.S3Options.Validate()...) errs = append(errs, s.OpenPitrixOptions.Validate()...) errs = append(errs, s.NetworkOptions.Validate()...) + errs = append(errs, s.LdapOptions.Validate()...) return errs } diff --git a/cmd/controller-manager/app/server.go b/cmd/controller-manager/app/server.go index 8c2c7bdf8..449dd0d58 100644 --- a/cmd/controller-manager/app/server.go +++ b/cmd/controller-manager/app/server.go @@ -40,6 +40,7 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/devops" "kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins" "kubesphere.io/kubesphere/pkg/simple/client/k8s" + ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" "kubesphere.io/kubesphere/pkg/utils/term" @@ -58,6 +59,7 @@ func NewControllerManagerCommand() *cobra.Command { KubernetesOptions: conf.KubernetesOptions, DevopsOptions: conf.DevopsOptions, S3Options: conf.S3Options, + LdapOptions: conf.LdapOptions, OpenPitrixOptions: conf.OpenPitrixOptions, NetworkOptions: conf.NetworkOptions, MultiClusterOptions: conf.MultiClusterOptions, @@ -114,6 +116,22 @@ func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) } } + var ldapClient ldapclient.Interface + if s.LdapOptions == nil || len(s.LdapOptions.Host) == 0 { + klog.Errorf("Failed to create devops client invalid ldap options") + return err + } + + if s.LdapOptions.Host == ldapclient.FAKE_HOST { + ldapClient = ldapclient.NewSimpleLdap() + } else { + ldapClient, err = ldapclient.NewLdapClient(s.LdapOptions, stopCh) + if err != nil { + klog.Errorf("Failed to create ldap client %v", err) + return err + } + } + var openpitrixClient openpitrix.Client if s.OpenPitrixOptions != nil && !s.OpenPitrixOptions.IsEmpty() { openpitrixClient, err = openpitrix.NewClient(s.OpenPitrixOptions) @@ -160,7 +178,8 @@ func Run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) // TODO(jeff): refactor config with CRD servicemeshEnabled := s.ServiceMeshOptions != nil && len(s.ServiceMeshOptions.IstioPilotHost) != 0 - if err = addControllers(mgr, kubernetesClient, informerFactory, devopsClient, s3Client, openpitrixClient, s.MultiClusterOptions.Enable, s.NetworkOptions.EnableNetworkPolicy, servicemeshEnabled, stopCh); err != nil { + if err = addControllers(mgr, kubernetesClient, informerFactory, devopsClient, s3Client, ldapClient, openpitrixClient, + s.MultiClusterOptions.Enable, s.NetworkOptions.EnableNetworkPolicy, servicemeshEnabled, stopCh); err != nil { klog.Fatalf("unable to register controllers to the manager: %v", err) } diff --git a/cmd/ks-apiserver/app/options/options.go b/cmd/ks-apiserver/app/options/options.go index 219ff56b6..c453c57ac 100644 --- a/cmd/ks-apiserver/app/options/options.go +++ b/cmd/ks-apiserver/app/options/options.go @@ -15,7 +15,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins" eventsclient "kubesphere.io/kubesphere/pkg/simple/client/events/elasticsearch" "kubesphere.io/kubesphere/pkg/simple/client/k8s" - "kubesphere.io/kubesphere/pkg/simple/client/ldap" esclient "kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch" "kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" @@ -53,7 +52,6 @@ func (s *ServerRunOptions) Flags() (fss cliflag.NamedFlagSets) { s.AuthorizationOptions.AddFlags(fss.FlagSet("authorization"), s.AuthorizationOptions) s.DevopsOptions.AddFlags(fss.FlagSet("devops"), s.DevopsOptions) s.SonarQubeOptions.AddFlags(fss.FlagSet("sonarqube"), s.SonarQubeOptions) - s.LdapOptions.AddFlags(fss.FlagSet("ldap"), s.LdapOptions) s.RedisOptions.AddFlags(fss.FlagSet("redis"), s.RedisOptions) s.S3Options.AddFlags(fss.FlagSet("s3"), s.S3Options) s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"), s.OpenPitrixOptions) @@ -138,18 +136,6 @@ func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIS apiServer.SonarClient = sonarqube.NewSonar(sonarClient.SonarQube()) } - if s.LdapOptions.Host != "" { - if s.LdapOptions.Host == fakeInterface && s.DebugMode { - apiServer.LdapClient = ldap.NewSimpleLdap() - } else { - ldapClient, err := ldap.NewLdapClient(s.LdapOptions, stopCh) - if err != nil { - return nil, err - } - apiServer.LdapClient = ldapClient - } - } - var cacheClient cache.Interface if s.RedisOptions.Host != "" { if s.RedisOptions.Host == fakeInterface && s.DebugMode { diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index a46518494..0ef6a8bc2 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -69,7 +69,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/devops" "kubesphere.io/kubesphere/pkg/simple/client/events" "kubesphere.io/kubesphere/pkg/simple/client/k8s" - "kubesphere.io/kubesphere/pkg/simple/client/ldap" "kubesphere.io/kubesphere/pkg/simple/client/logging" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" @@ -131,9 +130,6 @@ type APIServer struct { // S3Client s3.Interface - // - LdapClient ldap.Interface - SonarClient sonarqube.SonarInterface EventsClient events.Client diff --git a/pkg/controller/user/user_controller.go b/pkg/controller/user/user_controller.go index 83c92a17c..1137a7b02 100644 --- a/pkg/controller/user/user_controller.go +++ b/pkg/controller/user/user_controller.go @@ -43,6 +43,8 @@ import ( userlister "kubesphere.io/kubesphere/pkg/client/listers/iam/v1alpha2" "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/models/kubeconfig" + ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" "reflect" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "strconv" @@ -67,6 +69,7 @@ type Controller struct { cmSynced cache.InformerSynced fedUserCache cache.Store fedUserController cache.Controller + ldapClient ldapclient.Interface // workqueue is a rate limited work queue. This is used to queue work to be // processed instead of performing it as soon as a change happens. This // means we can ensure we only process a fixed amount of resources at a @@ -81,7 +84,7 @@ type Controller struct { func NewController(k8sClient kubernetes.Interface, ksClient kubesphere.Interface, config *rest.Config, userInformer userinformer.UserInformer, fedUserCache cache.Store, fedUserController cache.Controller, - configMapInformer corev1informers.ConfigMapInformer, multiClusterEnabled bool) *Controller { + configMapInformer corev1informers.ConfigMapInformer, ldapClient ldapclient.Interface, multiClusterEnabled bool) *Controller { // Create event broadcaster // Add sample-controller types to the default Kubernetes Scheme so Events can be // logged for sample-controller types. @@ -106,6 +109,7 @@ func NewController(k8sClient kubernetes.Interface, ksClient kubesphere.Interface cmSynced: configMapInformer.Informer().HasSynced, fedUserCache: fedUserCache, fedUserController: fedUserController, + ldapClient: ldapClient, workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Users"), recorder: recorder, multiClusterEnabled: multiClusterEnabled, @@ -239,6 +243,48 @@ func (c *Controller) reconcile(key string) error { return err } + // name of your custom finalizer + finalizer := "finalizers.kubesphere.io/users" + + if user.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !sliceutil.HasString(user.Finalizers, finalizer) { + user.ObjectMeta.Finalizers = append(user.ObjectMeta.Finalizers, finalizer) + + if user, err = c.ksClient.IamV1alpha2().Users().Update(user); err != nil { + return err + } + } + } else { + // The object is being deleted + if sliceutil.HasString(user.ObjectMeta.Finalizers, finalizer) { + + klog.V(4).Infof("delete user %s", key) + if err = c.ldapClient.Delete(key); err != nil && err != ldapclient.ErrUserNotExists { + klog.Error(err) + return err + } + + // remove our finalizer from the list and update it. + user.Finalizers = sliceutil.RemoveString(user.ObjectMeta.Finalizers, func(item string) bool { + return item == finalizer + }) + + if _, err := c.ksClient.IamV1alpha2().Users().Update(user); err != nil { + return err + } + } + + // Our finalizer has finished, so the reconciler can do nothing. + return nil + } + + if err = c.ldapSync(user); err != nil { + klog.Error(err) + return err + } + if user, err = c.ensurePasswordIsEncrypted(user); err != nil { klog.Error(err) return err @@ -269,9 +315,9 @@ func (c *Controller) Start(stopCh <-chan struct{}) error { } func (c *Controller) ensurePasswordIsEncrypted(user *iamv1alpha2.User) (*iamv1alpha2.User, error) { - encrypted, err := strconv.ParseBool(user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]) + encrypted, _ := strconv.ParseBool(user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]) // password is not encrypted - if err != nil || !encrypted { + if !encrypted { password, err := encrypt(user.Spec.EncryptedPassword) if err != nil { klog.Error(err) @@ -282,7 +328,6 @@ func (c *Controller) ensurePasswordIsEncrypted(user *iamv1alpha2.User) (*iamv1al if user.Annotations == nil { user.Annotations = make(map[string]string, 0) } - user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation] = "true" user.Status.State = iamv1alpha2.UserActive return c.ksClient.IamV1alpha2().Users().Update(user) @@ -419,6 +464,25 @@ func (c *Controller) updateFederatedUser(fedUser *iamv1alpha2.FederatedUser) err return nil } +func (c *Controller) ldapSync(user *iamv1alpha2.User) error { + encrypted, _ := strconv.ParseBool(user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]) + if encrypted { + return nil + } + _, err := c.ldapClient.Get(user.Name) + if err != nil { + if err == ldapclient.ErrUserNotExists { + klog.V(4).Infof("create user %s", user.Name) + return c.ldapClient.Create(user) + } + klog.Error(err) + return err + } else { + klog.V(4).Infof("update user %s", user.Name) + return c.ldapClient.Update(user) + } +} + func encrypt(password string) (string, error) { // when user is already mapped to another identity, password is empty by default // unable to log in directly until password reset diff --git a/pkg/controller/user/user_controller_test.go b/pkg/controller/user/user_controller_test.go index 01894afed..7018fb89a 100644 --- a/pkg/controller/user/user_controller_test.go +++ b/pkg/controller/user/user_controller_test.go @@ -29,6 +29,7 @@ import ( iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" "reflect" "testing" "time" @@ -81,6 +82,7 @@ func newUser(name string) *iamv1alpha2.User { func (f *fixture) newController() (*Controller, ksinformers.SharedInformerFactory, kubeinformers.SharedInformerFactory) { f.ksclient = fake.NewSimpleClientset(f.objects...) f.k8sclient = k8sfake.NewSimpleClientset(f.kubeobjects...) + ldapClient := ldapclient.NewSimpleLdap() ksinformers := ksinformers.NewSharedInformerFactory(f.ksclient, noResyncPeriodFunc()) k8sinformers := kubeinformers.NewSharedInformerFactory(f.k8sclient, noResyncPeriodFunc()) @@ -92,7 +94,7 @@ func (f *fixture) newController() (*Controller, ksinformers.SharedInformerFactor } } - c := NewController(f.k8sclient, f.ksclient, nil, ksinformers.Iam().V1alpha2().Users(), nil, nil, k8sinformers.Core().V1().ConfigMaps(), false) + c := NewController(f.k8sclient, f.ksclient, nil, ksinformers.Iam().V1alpha2().Users(), nil, nil, k8sinformers.Core().V1().ConfigMaps(), ldapClient, false) c.userSynced = alwaysReady c.recorder = &record.FakeRecorder{} @@ -208,6 +210,7 @@ func filterInformerActions(actions []core.Action) []core.Action { var ret []core.Action for _, action := range actions { if action.Matches("list", "users") || + action.Matches("list", "configmaps") || action.Matches("watch", "users") { continue } @@ -219,9 +222,14 @@ func filterInformerActions(actions []core.Action) []core.Action { func (f *fixture) expectUpdateUserStatusAction(user *iamv1alpha2.User) { expect := user.DeepCopy() + expect.Finalizers = []string{"finalizers.kubesphere.io/users"} + action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "users"}, "", expect) + f.actions = append(f.actions, action) + + expect = expect.DeepCopy() expect.Status.State = iamv1alpha2.UserActive expect.Annotations = map[string]string{iamv1alpha2.PasswordEncryptedAnnotation: "true"} - action := core.NewUpdateAction(schema.GroupVersionResource{Resource: "users"}, "", expect) + action = core.NewUpdateAction(schema.GroupVersionResource{Resource: "users"}, "", expect) f.actions = append(f.actions, action) } diff --git a/pkg/simple/client/ldap/ldap.go b/pkg/simple/client/ldap/ldap.go index f2f62bd5f..d2272789c 100644 --- a/pkg/simple/client/ldap/ldap.go +++ b/pkg/simple/client/ldap/ldap.go @@ -19,7 +19,6 @@ package ldap import ( "fmt" "github.com/go-ldap/ldap" - "github.com/google/uuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api" @@ -184,7 +183,7 @@ func (l *ldapInterfaceImpl) dnForUsername(username string) string { } func (l *ldapInterfaceImpl) filterForUsername(username string) string { - return fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=%s)(mail=%s)))", username, username) + return fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(%s=%s)(%s=%s)))", ldapAttributeUserID, username, ldapAttributeMail, username) } func (l *ldapInterfaceImpl) Get(name string) (*iamv1alpha2.User, error) { @@ -205,7 +204,6 @@ func (l *ldapInterfaceImpl) Get(name string) (*iamv1alpha2.User, error) { Attributes: []string{ ldapAttributeMail, ldapAttributeDescription, - ldapAttributePreferredLanguage, ldapAttributeCreateTimestamp, }, } @@ -215,7 +213,7 @@ func (l *ldapInterfaceImpl) Get(name string) (*iamv1alpha2.User, error) { return nil, err } - if len(searchResults.Entries) != 1 { + if len(searchResults.Entries) == 0 { return nil, ErrUserNotExists } @@ -227,28 +225,22 @@ func (l *ldapInterfaceImpl) Get(name string) (*iamv1alpha2.User, error) { }, Spec: iamv1alpha2.UserSpec{ Email: userEntry.GetAttributeValue(ldapAttributeMail), - Lang: userEntry.GetAttributeValue(ldapAttributePreferredLanguage), Description: userEntry.GetAttributeValue(ldapAttributeDescription), }, } createTimestamp, _ := time.Parse(ldapAttributeCreateTimestampLayout, userEntry.GetAttributeValue(ldapAttributeCreateTimestamp)) user.ObjectMeta.CreationTimestamp.Time = createTimestamp - return user, nil } func (l *ldapInterfaceImpl) Create(user *iamv1alpha2.User) error { - if _, err := l.Get(user.Name); err != nil { - return ErrUserAlreadyExisted - } - createRequest := &ldap.AddRequest{ DN: l.dnForUsername(user.Name), Attributes: []ldap.Attribute{ { Type: ldapAttributeObjectClass, - Vals: []string{"inetOrgPerson", "posixAccount", "top"}, + Vals: []string{"inetOrgPerson", "top"}, }, { Type: ldapAttributeCommonName, @@ -256,40 +248,12 @@ func (l *ldapInterfaceImpl) Create(user *iamv1alpha2.User) error { }, { Type: ldapAttributeSerialNumber, - Vals: []string{" "}, - }, - { - Type: ldapAttributeGlobalIDNumber, - Vals: []string{"500"}, - }, - { - Type: ldapAttributeHomeDirectory, - Vals: []string{"/home/" + user.Name}, - }, - { - Type: ldapAttributeUserID, Vals: []string{user.Name}, }, - { - Type: ldapAttributeUserIDNumber, - Vals: []string{uuid.New().String()}, - }, - { - Type: ldapAttributeMail, - Vals: []string{user.Spec.Email}, - }, { Type: ldapAttributeUserPassword, Vals: []string{user.Spec.EncryptedPassword}, }, - { - Type: ldapAttributePreferredLanguage, - Vals: []string{user.Spec.Lang}, - }, - { - Type: ldapAttributeDescription, - Vals: []string{user.Spec.Description}, - }, }, } @@ -341,14 +305,6 @@ func (l *ldapInterfaceImpl) Update(newUser *iamv1alpha2.User) error { DN: l.dnForUsername(newUser.Name), } - if newUser.Spec.Description != "" { - modifyRequest.Replace(ldapAttributeDescription, []string{newUser.Spec.Description}) - } - - if newUser.Spec.Lang != "" { - modifyRequest.Replace(ldapAttributePreferredLanguage, []string{newUser.Spec.Lang}) - } - if newUser.Spec.EncryptedPassword != "" { modifyRequest.Replace(ldapAttributeUserPassword, []string{newUser.Spec.EncryptedPassword}) } @@ -385,55 +341,37 @@ func (l *ldapInterfaceImpl) List(query *query.Query) (*api.ListResult, error) { filter := "(&(objectClass=inetOrgPerson))" - if keyword := query.Filters["keyword"]; keyword != "" { - filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword) - } - - if username := query.Filters["username"]; username != "" { - uidFilter := "" - for _, username := range strings.Split(string(username), "|") { - uidFilter += fmt.Sprintf("(uid=%s)", username) - } - filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", uidFilter) - } - - if email := query.Filters["email"]; email != "" { - emailFilter := "" - for _, username := range strings.Split(string(email), "|") { - emailFilter += fmt.Sprintf("(mail=%s)", username) - } - filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", emailFilter) - } - for { userSearchRequest := ldap.NewSearchRequest( l.userSearchBase, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, filter, - []string{"uid", "mail", "description", "preferredLanguage", "createTimestamp"}, + []string{ldapAttributeUserID, ldapAttributeMail, ldapAttributeDescription, ldapAttributeCreateTimestamp}, []ldap.Control{pageControl}, ) response, err := conn.Search(userSearchRequest) if err != nil { - klog.Errorln("search user", err) + klog.Error(err) return nil, err } for _, entry := range response.Entries { - uid := entry.GetAttributeValue("uid") - email := entry.GetAttributeValue("mail") - description := entry.GetAttributeValue("description") - lang := entry.GetAttributeValue("preferredLanguage") - createTimestamp, _ := time.Parse("20060102150405Z", entry.GetAttributeValue("createTimestamp")) + uid := entry.GetAttributeValue(ldapAttributeUserID) + email := entry.GetAttributeValue(ldapAttributeMail) + description := entry.GetAttributeValue(ldapAttributeDescription) + createTimestamp, _ := time.Parse(ldapAttributeCreateTimestampLayout, entry.GetAttributeValue(ldapAttributeCreateTimestamp)) - user := iamv1alpha2.User{ObjectMeta: metav1.ObjectMeta{Name: uid, CreationTimestamp: metav1.Time{Time: createTimestamp}}, Spec: iamv1alpha2.UserSpec{ - Email: email, - Lang: lang, - Description: description, - }} + user := iamv1alpha2.User{ + ObjectMeta: metav1.ObjectMeta{ + Name: uid, + CreationTimestamp: metav1.Time{Time: createTimestamp}}, + Spec: iamv1alpha2.UserSpec{ + Email: email, + Description: description, + }} users = append(users, user) } diff --git a/pkg/simple/client/ldap/simple_ldap.go b/pkg/simple/client/ldap/simple_ldap.go index f347c29e0..2fe3df104 100644 --- a/pkg/simple/client/ldap/simple_ldap.go +++ b/pkg/simple/client/ldap/simple_ldap.go @@ -23,6 +23,8 @@ import ( "kubesphere.io/kubesphere/pkg/apiserver/query" ) +const FAKE_HOST string = "FAKE" + // simpleLdap is a implementation of ldap.Interface, you should never use this in production env! type simpleLdap struct { store map[string]*iamv1alpha2.User