im.go 30.8 KB
Newer Older
H
hongming 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*

 Copyright 2019 The KubeSphere Authors.

 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 iam

import (
H
hongming 已提交
21
	"encoding/json"
H
hongming 已提交
22 23
	"errors"
	"fmt"
R
runzexia 已提交
24
	"github.com/emicklei/go-restful"
H
hongming 已提交
25 26 27
	"github.com/go-ldap/ldap"
	"github.com/go-redis/redis"
	"golang.org/x/oauth2"
H
hongming 已提交
28
	"io/ioutil"
29
	"k8s.io/klog"
H
hongming 已提交
30
	"kubesphere.io/kubesphere/pkg/constants"
R
runzexia 已提交
31
	"kubesphere.io/kubesphere/pkg/db"
H
hongming 已提交
32
	"kubesphere.io/kubesphere/pkg/informers"
R
runzexia 已提交
33
	"kubesphere.io/kubesphere/pkg/models/devops"
H
hongming 已提交
34 35
	"kubesphere.io/kubesphere/pkg/models/kubeconfig"
	"kubesphere.io/kubesphere/pkg/models/kubectl"
J
Jeff 已提交
36
	"kubesphere.io/kubesphere/pkg/server/params"
37
	clientset "kubesphere.io/kubesphere/pkg/simple/client"
H
hongming 已提交
38
	ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
H
hongming 已提交
39
	"kubesphere.io/kubesphere/pkg/utils/k8sutil"
H
hongming 已提交
40
	"kubesphere.io/kubesphere/pkg/utils/sliceutil"
R
runzexia 已提交
41
	"net/http"
H
hongming 已提交
42
	"regexp"
H
hongming 已提交
43
	"sort"
H
hongming 已提交
44 45 46 47 48
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
49
	rbacv1 "k8s.io/api/rbac/v1"
50
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
H
hongming 已提交
51 52
	"k8s.io/apimachinery/pkg/labels"
	"kubesphere.io/kubesphere/pkg/models"
H
hongming 已提交
53
	"kubesphere.io/kubesphere/pkg/utils/jwtutil"
H
hongming 已提交
54 55
)

H
hongming 已提交
56 57 58 59 60 61 62 63 64 65 66 67
type IdentityManagementInterface interface {
	CreateUser(user *User) (*User, error)
	DescribeUser(username string) (*User, error)
	Login(username, password, ip string) (*oauth2.Token, error)
}

type imOperator struct {
	config    Config
	ldap      ldappool.Client
	redis     redis.Client
	initUsers []initUser
}
H
hongming 已提交
68

H
hongming 已提交
69
type initUser struct {
H
hongming 已提交
70
	User
H
hongming 已提交
71 72 73
	Hidden bool `json:"hidden"`
}

H
hongming 已提交
74
const (
H
hongming 已提交
75 76 77 78 79 80 81 82 83
	authRateLimitRegex         = `(\d+)/(\d+[s|m|h])`
	defaultMaxAuthFailed       = 5
	defaultAuthTimeInterval    = 30 * time.Minute
	mailAttribute              = "mail"
	uidAttribute               = "uid"
	descriptionAttribute       = "description"
	preferredLanguageAttribute = "preferredLanguage"
	createTimestampAttribute   = "createTimestampAttribute"
	dateTimeLayout             = "20060102150405Z"
H
hongming 已提交
84 85
)

H
hongming 已提交
86
func IdentityManagementInit(ldap ldappool.Client, config Config) (IdentityManagementInterface, error) {
H
hongming 已提交
87

H
hongming 已提交
88 89 90 91 92
	//maxAuthFailed, authTimeInterval := parseAuthRateLimit(authRateLimit)

	imOperator := &imOperator{ldap: ldap, config: config}

	err := imOperator.checkAndCreateDefaultUser()
H
hongming 已提交
93

H
hongming 已提交
94
	if err != nil {
H
hongming 已提交
95 96
		klog.Errorln(err)
		return nil, err
H
hongming 已提交
97 98
	}

H
hongming 已提交
99
	err = imOperator.checkAndCreateDefaultGroup()
H
hongming 已提交
100

H
hongming 已提交
101
	if err != nil {
H
hongming 已提交
102 103
		klog.Errorln(err)
		return nil, err
H
hongming 已提交
104 105
	}

H
hongming 已提交
106
	return imOperator, nil
H
hongming 已提交
107 108
}

109 110 111 112 113 114 115 116 117 118 119
func parseAuthRateLimit(authRateLimit string) (int, time.Duration) {
	regex := regexp.MustCompile(authRateLimitRegex)
	groups := regex.FindStringSubmatch(authRateLimit)

	maxCount := defaultMaxAuthFailed
	timeInterval := defaultAuthTimeInterval

	if len(groups) == 3 {
		maxCount, _ = strconv.Atoi(groups[1])
		timeInterval, _ = time.ParseDuration(groups[2])
	} else {
120
		klog.Warning("invalid auth rate limit", authRateLimit)
121 122 123 124 125
	}

	return maxCount, timeInterval
}

H
hongming 已提交
126
func (im *imOperator) checkAndCreateDefaultGroup() error {
H
hongming 已提交
127

H
hongming 已提交
128
	conn, err := im.ldap.NewConn()
H
hongming 已提交
129 130 131 132
	if err != nil {
		return err
	}
	defer conn.Close()
H
hongming 已提交
133 134

	groupSearchRequest := ldap.NewSearchRequest(
H
hongming 已提交
135
		im.ldap.GroupSearchBase(),
H
hongming 已提交
136
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
H
hongming 已提交
137
		"(&(objectClass=posixGroup))",
H
hongming 已提交
138 139 140 141
		nil,
		nil,
	)

H
hongming 已提交
142
	_, err = conn.Search(groupSearchRequest)
H
hongming 已提交
143

H
hongming 已提交
144
	if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
H
hongming 已提交
145
		err = im.createGroupsBaseDN()
Z
zryfish 已提交
146
		if err != nil {
H
hongming 已提交
147
			return fmt.Errorf("GroupBaseDN %s create failed: %s\n", im.ldap.GroupSearchBase(), err)
Z
zryfish 已提交
148
		}
H
hongming 已提交
149 150
	}

H
hongming 已提交
151
	if err != nil {
Z
zryfish 已提交
152
		return fmt.Errorf("iam database init failed: %s\n", err)
H
hongming 已提交
153
	}
H
hongming 已提交
154

H
hongming 已提交
155 156 157
	return nil
}

H
hongming 已提交
158 159
func (im *imOperator) checkAndCreateDefaultUser() error {
	conn, err := im.ldap.NewConn()
H
hongming 已提交
160 161 162 163
	if err != nil {
		return err
	}
	defer conn.Close()
H
hongming 已提交
164 165

	userSearchRequest := ldap.NewSearchRequest(
H
hongming 已提交
166
		im.ldap.UserSearchBase(),
H
hongming 已提交
167
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
H
hongming 已提交
168
		"(&(objectClass=inetOrgPerson))",
H
hongming 已提交
169
		[]string{"uid"},
H
hongming 已提交
170 171 172
		nil,
	)

H
hongming 已提交
173
	result, err := conn.Search(userSearchRequest)
H
hongming 已提交
174

H
hongming 已提交
175
	if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
H
hongming 已提交
176
		err = im.createUserBaseDN()
Z
zryfish 已提交
177
		if err != nil {
H
hongming 已提交
178
			return fmt.Errorf("UserBaseDN %s create failed: %s\n", im.ldap.UserSearchBase(), err)
Z
zryfish 已提交
179
		}
H
hongming 已提交
180 181
	}

H
hongming 已提交
182
	if err != nil {
Z
zryfish 已提交
183
		return fmt.Errorf("iam database init failed: %s\n", err)
H
hongming 已提交
184
	}
H
hongming 已提交
185

H
hongming 已提交
186 187
	data, err := ioutil.ReadFile(im.config.userInitFile)

H
hongming 已提交
188
	if err == nil {
H
hongming 已提交
189
		json.Unmarshal(data, &im.initUsers)
H
hongming 已提交
190 191
	}

H
hongming 已提交
192 193 194
	im.initUsers = append(im.initUsers, initUser{User: User{Username: constants.AdminUserName, Email: im.config.adminEmail, Password: im.config.adminPassword, Description: "Administrator account that was always created by default.", ClusterRole: constants.ClusterAdmin}})

	for _, user := range im.initUsers {
H
hongming 已提交
195
		if result == nil || !containsUser(result.Entries, user) {
H
hongming 已提交
196
			_, err = im.CreateUser(&user.User)
H
hongming 已提交
197
			if err != nil && !ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
H
hongming 已提交
198 199
				klog.Errorln(err)
				return err
H
hongming 已提交
200
			}
H
hongming 已提交
201 202 203 204 205 206
		}
	}

	return nil
}

H
hongming 已提交
207 208 209 210 211 212 213 214 215 216
func containsUser(entries []*ldap.Entry, user initUser) bool {
	for _, entry := range entries {
		uid := entry.GetAttributeValue("uid")
		if uid == user.Username {
			return true
		}
	}
	return false
}

H
hongming 已提交
217
func (im *imOperator) createUserBaseDN() error {
H
hongming 已提交
218

H
hongming 已提交
219
	conn, err := im.ldap.NewConn()
H
hongming 已提交
220 221 222
	if err != nil {
		return err
	}
H
hongming 已提交
223
	defer conn.Close()
H
hongming 已提交
224
	groupsCreateRequest := ldap.NewAddRequest(im.ldap.UserSearchBase(), nil)
H
hongming 已提交
225 226
	groupsCreateRequest.Attribute("objectClass", []string{"organizationalUnit", "top"})
	groupsCreateRequest.Attribute("ou", []string{"Users"})
H
hongming 已提交
227
	return conn.Add(groupsCreateRequest)
H
hongming 已提交
228 229
}

H
hongming 已提交
230
func (im *imOperator) createGroupsBaseDN() error {
H
hongming 已提交
231

H
hongming 已提交
232
	conn, err := im.ldap.NewConn()
H
hongming 已提交
233 234 235
	if err != nil {
		return err
	}
H
hongming 已提交
236
	defer conn.Close()
H
hongming 已提交
237
	groupsCreateRequest := ldap.NewAddRequest(im.ldap.GroupSearchBase(), nil)
H
hongming 已提交
238 239
	groupsCreateRequest.Attribute("objectClass", []string{"organizationalUnit", "top"})
	groupsCreateRequest.Attribute("ou", []string{"Groups"})
H
hongming 已提交
240
	return conn.Add(groupsCreateRequest)
H
hongming 已提交
241 242
}

H
hongming 已提交
243 244
// User login
func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error) {
245

H
hongming 已提交
246
	records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", username)).Result()
247 248 249 250 251 252

	if err != nil {
		klog.Error(err)
		return nil, err
	}

H
hongming 已提交
253
	if len(records) >= im.config.maxAuthFailed {
254 255 256
		return nil, restful.NewError(http.StatusTooManyRequests, "auth rate limit exceeded")
	}

H
hongming 已提交
257
	user, err := im.DescribeUser(&User{Username: username, Email: username})
258

H
hongming 已提交
259
	conn, err := im.ldap.NewConn()
260
	if err != nil {
261
		klog.Error(err)
262 263
		return nil, err
	}
H
hongming 已提交
264
	defer conn.Close()
H
hongming 已提交
265

H
hongming 已提交
266
	dn := fmt.Sprintf("%s=%s,%s", uidAttribute, user.Username, im.ldap.UserSearchBase())
H
hongming 已提交
267 268

	// bind as the user to verify their password
H
hongming 已提交
269
	err = conn.Bind(dn, password)
H
hongming 已提交
270 271

	if err != nil {
272
		if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
H
hongming 已提交
273 274
			authFailedCacheKey := fmt.Sprintf("kubesphere:authfailed:%s:%d", user.Username, time.Now().UnixNano())
			im.redis.Set(authFailedCacheKey, "", im.config.authTimeInterval)
275
		}
H
hongming 已提交
276
		return nil, err
H
hongming 已提交
277 278 279 280
	}

	claims := jwt.MapClaims{}

H
hongming 已提交
281
	loginTime := time.Now()
282
	// token without expiration time will auto sliding
H
hongming 已提交
283 284 285
	claims["username"] = user.Username
	claims["email"] = user.Email
	claims["iat"] = loginTime.Unix()
H
hongming 已提交
286

H
hongming 已提交
287
	token := jwtutil.MustSigned(claims)
H
hongming 已提交
288

H
hongming 已提交
289
	if !im.config.enableMultiLogin {
H
hongming 已提交
290
		// multi login not allowed, remove the previous token
H
hongming 已提交
291 292
		sessionCacheKey := fmt.Sprintf("kubesphere:users:%s:token:*", user.Username)
		sessions, err := im.redis.Keys(sessionCacheKey).Result()
H
hongming 已提交
293 294 295 296 297 298 299 300

		if err != nil {
			klog.Errorln(err)
			return nil, err
		}

		if len(sessions) > 0 {
			klog.V(4).Infoln("revoke token", sessions)
H
hongming 已提交
301
			err = im.redis.Del(sessions...).Err()
H
hongming 已提交
302 303 304 305 306 307 308 309
			if err != nil {
				klog.Errorln(err)
				return nil, err
			}
		}
	}

	// cache token with expiration time
H
hongming 已提交
310 311
	sessionCacheKey := fmt.Sprintf("kubesphere:users:%s:token:%s", user.Username, token)
	if err = im.redis.Set(sessionCacheKey, token, im.config.tokenIdleTimeout).Err(); err != nil {
H
hongming 已提交
312 313 314 315
		klog.Errorln(err)
		return nil, err
	}

H
hongming 已提交
316
	im.loginRecord(user.Username, ip, loginTime)
Z
zryfish 已提交
317

H
hongming 已提交
318
	return &oauth2.Token{AccessToken: token}, nil
H
hongming 已提交
319 320
}

H
hongming 已提交
321
func (im *imOperator) loginRecord(username, ip string, loginTime time.Time) {
Z
zryfish 已提交
322
	if ip != "" {
H
hongming 已提交
323 324
		im.redis.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", username), fmt.Sprintf("%s,%s", loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip))
		im.redis.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1)
Z
zryfish 已提交
325 326 327
	}
}

H
hongming 已提交
328 329
func (im *imOperator) LoginHistory(username string) ([]string, error) {
	data, err := im.redis.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -10, -1).Result()
H
hongming 已提交
330 331 332 333 334 335 336 337

	if err != nil {
		return nil, err
	}

	return data, nil
}

H
hongming 已提交
338 339
func (im *imOperator) ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
	conn, err := im.ldap.NewConn()
H
hongming 已提交
340 341 342 343
	if err != nil {
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
344

H
hongming 已提交
345
	pageControl := ldap.NewControlPaging(1000)
H
hongming 已提交
346

H
hongming 已提交
347
	users := make([]User, 0)
H
hongming 已提交
348

H
hongming 已提交
349
	filter := "(&(objectClass=inetOrgPerson))"
H
hongming 已提交
350

H
hongming 已提交
351 352 353
	if keyword := conditions.Match["keyword"]; keyword != "" {
		filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword)
	}
H
hongming 已提交
354

H
hongming 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
	if username := conditions.Match["username"]; username != "" {
		uidFilter := ""
		for _, username := range strings.Split(username, "|") {
			uidFilter += fmt.Sprintf("(uid=%s)", username)
		}
		filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", uidFilter)
	}

	if email := conditions.Match["email"]; email != "" {
		emailFilter := ""
		for _, username := range strings.Split(email, "|") {
			emailFilter += fmt.Sprintf("(mail=%s)", username)
		}
		filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", emailFilter)
	}

H
hongming 已提交
371 372
	for {
		userSearchRequest := ldap.NewSearchRequest(
H
hongming 已提交
373
			im.ldap.UserSearchBase(),
H
hongming 已提交
374
			ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
H
hongming 已提交
375 376
			filter,
			[]string{"uid", "mail", "description", "preferredLanguage", "createTimestamp"},
H
hongming 已提交
377 378 379
			[]ldap.Control{pageControl},
		)

H
hongming 已提交
380
		response, err := conn.Search(userSearchRequest)
H
hongming 已提交
381 382

		if err != nil {
383
			klog.Errorln("search user", err)
H
hongming 已提交
384
			return nil, err
H
hongming 已提交
385 386 387
		}

		for _, entry := range response.Entries {
H
hongming 已提交
388 389 390 391 392 393 394

			uid := entry.GetAttributeValue("uid")
			email := entry.GetAttributeValue("mail")
			description := entry.GetAttributeValue("description")
			lang := entry.GetAttributeValue("preferredLanguage")
			createTimestamp, _ := time.Parse("20060102150405Z", entry.GetAttributeValue("createTimestamp"))

H
hongming 已提交
395
			user := User{Username: uid, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
H
hongming 已提交
396

H
hongming 已提交
397
			if !im.shouldHidden(user) {
H
hongming 已提交
398 399
				users = append(users, user)
			}
H
hongming 已提交
400 401 402 403 404 405 406 407 408 409 410
		}

		updatedControl := ldap.FindControl(response.Controls, ldap.ControlTypePaging)
		if ctrl, ok := updatedControl.(*ldap.ControlPaging); ctrl != nil && ok && len(ctrl.Cookie) != 0 {
			pageControl.SetCookie(ctrl.Cookie)
			continue
		}

		break
	}

H
hongming 已提交
411 412 413 414 415 416 417 418
	sort.Slice(users, func(i, j int) bool {
		if reverse {
			tmp := i
			i = j
			j = tmp
		}
		switch orderBy {
		case "username":
H
hongming 已提交
419
			return strings.Compare(users[i].Username, users[j].Username) <= 0
H
hongming 已提交
420
		case "createTime":
H
hongming 已提交
421
			fallthrough
H
hongming 已提交
422
		default:
H
hongming 已提交
423
			return users[i].CreateTime.Before(users[j].CreateTime)
H
hongming 已提交
424 425
		}
	})
H
hongming 已提交
426

H
hongming 已提交
427
	items := make([]interface{}, 0)
H
hongming 已提交
428

H
hongming 已提交
429
	for i, user := range users {
H
hongming 已提交
430

H
hongming 已提交
431
		if i >= offset && len(items) < limit {
H
hongming 已提交
432

H
hongming 已提交
433 434
			user.LastLoginTime = im.GetLastLoginTime(user.Username)
			clusterRole, err := im.GetUserClusterRole(user.Username)
H
hongming 已提交
435 436 437 438 439 440
			if err != nil {
				return nil, err
			}
			user.ClusterRole = clusterRole.Name
			items = append(items, user)
		}
H
hongming 已提交
441 442
	}

H
hongming 已提交
443
	return &models.PageableResponse{Items: items, TotalCount: len(users)}, nil
H
hongming 已提交
444 445
}

H
hongming 已提交
446 447
func (im *imOperator) shouldHidden(user User) bool {
	for _, initUser := range im.initUsers {
H
hongming 已提交
448 449 450 451 452 453 454
		if initUser.Username == user.Username {
			return initUser.Hidden
		}
	}
	return false
}

H
hongming 已提交
455 456
func (im *imOperator) DescribeUser(user *User) (*User, error) {
	conn, err := im.ldap.NewConn()
H
hongming 已提交
457 458

	if err != nil {
H
hongming 已提交
459
		klog.Errorln(err)
H
hongming 已提交
460 461 462
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
463

H
hongming 已提交
464 465 466 467 468 469 470
	filter := fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=%s)(mail=%s)))", user.Username, user.Email)

	searchRequest := ldap.NewSearchRequest(
		im.ldap.UserSearchBase(),
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 1, 0, false,
		filter,
		[]string{mailAttribute, descriptionAttribute, preferredLanguageAttribute, createTimestampAttribute},
H
hongming 已提交
471 472 473
		nil,
	)

H
hongming 已提交
474
	result, err := conn.Search(searchRequest)
H
hongming 已提交
475 476

	if err != nil {
H
hongming 已提交
477
		klog.Errorln(err)
H
hongming 已提交
478 479 480 481
		return nil, err
	}

	if len(result.Entries) != 1 {
H
hongming 已提交
482
		return nil, ldap.NewError(ldap.LDAPResultNoSuchObject, errors.New("user does not exist"))
H
hongming 已提交
483 484
	}

H
hongming 已提交
485
	entry := result.Entries[0]
H
hongming 已提交
486

H
hongming 已提交
487
	return convertLdapEntryToUser(entry), nil
H
hongming 已提交
488 489
}

H
hongming 已提交
490 491 492 493 494 495 496
func convertLdapEntryToUser(entry *ldap.Entry) *User {
	username := entry.GetAttributeValue(uidAttribute)
	email := entry.GetAttributeValue(mailAttribute)
	description := entry.GetAttributeValue(descriptionAttribute)
	lang := entry.GetAttributeValue(preferredLanguageAttribute)
	createTimestamp, _ := time.Parse(dateTimeLayout, entry.GetAttributeValue(createTimestampAttribute))
	return &User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
H
hongming 已提交
497
}
H
hongming 已提交
498

H
hongming 已提交
499 500 501
func (im *imOperator) GetLastLoginTime(username string) string {
	cacheKey := fmt.Sprintf("kubesphere:users:%s:login-log", username)
	lastLogin, err := im.redis.LRange(cacheKey, -1, -1).Result()
H
hongming 已提交
502
	if err != nil {
H
hongming 已提交
503
		return ""
H
hongming 已提交
504 505
	}

H
hongming 已提交
506
	if len(lastLogin) > 0 {
H
hongming 已提交
507
		return strings.Split(lastLogin[0], ",")[0]
H
hongming 已提交
508
	}
H
hongming 已提交
509 510

	return ""
H
hongming 已提交
511 512
}

H
hongming 已提交
513 514
func (im *imOperator) DeleteUser(username string) error {
	conn, err := im.ldap.NewConn()
H
hongming 已提交
515 516 517 518
	if err != nil {
		return err
	}
	defer conn.Close()
H
hongming 已提交
519

H
hongming 已提交
520
	deleteRequest := ldap.NewDelRequest(fmt.Sprintf("uid=%s,%s", username, im.ldap.UserSearchBase()), nil)
H
hongming 已提交
521

H
hongming 已提交
522
	if err = conn.Del(deleteRequest); err != nil {
523
		klog.Errorln("delete user", err)
H
hongming 已提交
524 525 526
		return err
	}

H
hongming 已提交
527
	if err = im.deleteRoleBindings(username); err != nil {
528
		klog.Errorln("delete user role bindings failed", username, err)
H
hongming 已提交
529 530 531
	}

	if err := kubeconfig.DelKubeConfig(username); err != nil {
532
		klog.Errorln("delete user kubeconfig failed", username, err)
H
hongming 已提交
533
	}
H
hongming 已提交
534

H
hongming 已提交
535
	if err := kubectl.DelKubectlDeploy(username); err != nil {
536
		klog.Errorln("delete user terminal pod failed", username, err)
H
hongming 已提交
537 538
	}

H
hongming 已提交
539
	if err := im.deleteUserInDevOps(username); err != nil {
540 541 542 543 544 545 546
		klog.Errorln("delete user in devops failed", username, err)
	}
	return nil

}

// deleteUserInDevOps is used to clean up user data of devops, such as permission rules
H
hongming 已提交
547
func (im *imOperator) deleteUserInDevOps(username string) error {
548

549 550
	devopsDb, err := clientset.ClientSets().MySQL()
	if err != nil {
Z
zryfish 已提交
551 552
		if err == clientset.ErrClientSetNotEnabled {
			klog.Warning("mysql is not enable")
553 554
			return nil
		}
555 556
		return err
	}
R
runzexia 已提交
557

558 559
	dp, err := clientset.ClientSets().Devops()
	if err != nil {
Z
zryfish 已提交
560
		if err == clientset.ErrClientSetNotEnabled {
561 562 563
			klog.Warning("devops client is not enable")
			return nil
		}
564
		return err
R
runzexia 已提交
565
	}
566

567 568
	jenkinsClient := dp.Jenkins()

R
runzexia 已提交
569
	_, err = devopsDb.DeleteFrom(devops.ProjectMembershipTableName).
R
runzexia 已提交
570
		Where(db.And(
R
runzexia 已提交
571
			db.Eq(devops.ProjectMembershipUsernameColumn, username),
R
runzexia 已提交
572 573
		)).Exec()
	if err != nil {
574
		klog.Errorf("%+v", err)
R
runzexia 已提交
575
		return err
R
runzexia 已提交
576 577 578 579
	}

	err = jenkinsClient.DeleteUserInProject(username)
	if err != nil {
580
		klog.Errorf("%+v", err)
R
runzexia 已提交
581
		return err
R
runzexia 已提交
582
	}
H
hongming 已提交
583
	return nil
H
hongming 已提交
584 585
}

H
hongming 已提交
586
func (im *imOperator) deleteRoleBindings(username string) error {
H
hongming 已提交
587 588 589 590 591 592 593 594
	roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
	roleBindings, err := roleBindingLister.List(labels.Everything())

	if err != nil {
		return err
	}

	for _, roleBinding := range roleBindings {
H
hongming 已提交
595
		roleBinding = roleBinding.DeepCopy()
H
hongming 已提交
596 597 598
		length1 := len(roleBinding.Subjects)

		for index, subject := range roleBinding.Subjects {
599
			if subject.Kind == rbacv1.UserKind && subject.Name == username {
H
hongming 已提交
600 601 602 603 604 605 606 607
				roleBinding.Subjects = append(roleBinding.Subjects[:index], roleBinding.Subjects[index+1:]...)
				index--
			}
		}

		length2 := len(roleBinding.Subjects)

		if length2 == 0 {
H
hongming 已提交
608
			deletePolicy := metav1.DeletePropagationBackground
609
			err = clientset.ClientSets().K8s().Kubernetes().RbacV1().RoleBindings(roleBinding.Namespace).Delete(roleBinding.Name, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
H
hongming 已提交
610 611

			if err != nil {
612
				klog.Errorf("delete role binding %s %s %s failed: %v", username, roleBinding.Namespace, roleBinding.Name, err)
H
hongming 已提交
613 614
			}
		} else if length2 < length1 {
615
			_, err = clientset.ClientSets().K8s().Kubernetes().RbacV1().RoleBindings(roleBinding.Namespace).Update(roleBinding)
H
hongming 已提交
616 617

			if err != nil {
618
				klog.Errorf("update role binding %s %s %s failed: %v", username, roleBinding.Namespace, roleBinding.Name, err)
H
hongming 已提交
619 620 621 622 623 624 625 626
			}
		}
	}

	clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
	clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())

	for _, clusterRoleBinding := range clusterRoleBindings {
H
hongming 已提交
627
		clusterRoleBinding = clusterRoleBinding.DeepCopy()
H
hongming 已提交
628 629 630
		length1 := len(clusterRoleBinding.Subjects)

		for index, subject := range clusterRoleBinding.Subjects {
631
			if subject.Kind == rbacv1.UserKind && subject.Name == username {
H
hongming 已提交
632 633 634 635 636 637 638
				clusterRoleBinding.Subjects = append(clusterRoleBinding.Subjects[:index], clusterRoleBinding.Subjects[index+1:]...)
				index--
			}
		}

		length2 := len(clusterRoleBinding.Subjects)
		if length2 == 0 {
639 640
			// delete if it's not workspace role binding
			if isWorkspaceRoleBinding(clusterRoleBinding) {
641
				_, err = clientset.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
H
hongming 已提交
642
			} else {
H
hongming 已提交
643
				deletePolicy := metav1.DeletePropagationBackground
644
				err = clientset.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Delete(clusterRoleBinding.Name, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
H
hongming 已提交
645 646
			}
			if err != nil {
647
				klog.Errorf("update cluster role binding %s failed:%s", clusterRoleBinding.Name, err)
H
hongming 已提交
648 649
			}
		} else if length2 < length1 {
650
			_, err = clientset.ClientSets().K8s().Kubernetes().RbacV1().ClusterRoleBindings().Update(clusterRoleBinding)
H
hongming 已提交
651 652

			if err != nil {
653
				klog.Errorf("update cluster role binding %s failed:%s", clusterRoleBinding.Name, err)
H
hongming 已提交
654 655 656 657 658 659 660 661
			}
		}

	}

	return nil
}

H
hongming 已提交
662
func (im *imOperator) isWorkspaceRoleBinding(clusterRoleBinding *rbacv1.ClusterRoleBinding) bool {
663 664 665
	return k8sutil.IsControlledBy(clusterRoleBinding.OwnerReferences, "Workspace", "")
}

H
hongming 已提交
666
func (im *imOperator) CreateUser(user *User) (*User, error) {
H
hongming 已提交
667 668 669 670 671
	user.Username = strings.TrimSpace(user.Username)
	user.Email = strings.TrimSpace(user.Email)
	user.Password = strings.TrimSpace(user.Password)
	user.Description = strings.TrimSpace(user.Description)

H
hongming 已提交
672
	existed, err := im.DescribeUser(user)
H
hongming 已提交
673 674

	if err != nil {
H
hongming 已提交
675
		klog.Errorln(err)
H
hongming 已提交
676
		return nil, err
H
hongming 已提交
677 678
	}

H
hongming 已提交
679 680
	if existed != nil {
		return nil, ldap.NewError(ldap.LDAPResultEntryAlreadyExists, errors.New("username or email already exists"))
H
hongming 已提交
681 682
	}

H
hongming 已提交
683
	uidNumber := im.uidNumberNext()
H
hongming 已提交
684

H
hongming 已提交
685 686 687 688 689 690 691 692 693 694
	createRequest := ldap.NewAddRequest(fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase()), nil)
	createRequest.Attribute("objectClass", []string{"inetOrgPerson", "posixAccount", "top"})
	createRequest.Attribute("cn", []string{user.Username})                       // RFC4519: common name(s) for which the entity is known by
	createRequest.Attribute("sn", []string{" "})                                 // RFC2256: last (family) name(s) for which the entity is known by
	createRequest.Attribute("gidNumber", []string{"500"})                        // RFC2307: An integer uniquely identifying a group in an administrative domain
	createRequest.Attribute("homeDirectory", []string{"/home/" + user.Username}) // The absolute path to the home directory
	createRequest.Attribute("uid", []string{user.Username})                      // RFC4519: user identifier
	createRequest.Attribute("uidNumber", []string{strconv.Itoa(uidNumber)})      // RFC2307: An integer uniquely identifying a user in an administrative domain
	createRequest.Attribute("mail", []string{user.Email})                        // RFC1274: RFC822 Mailbox
	createRequest.Attribute("userPassword", []string{user.Password})             // RFC4519/2307: password of user
H
hongming 已提交
695
	if user.Lang != "" {
H
hongming 已提交
696
		createRequest.Attribute("preferredLanguage", []string{user.Lang})
H
hongming 已提交
697 698
	}
	if user.Description != "" {
H
hongming 已提交
699
		createRequest.Attribute("description", []string{user.Description}) // RFC4519: descriptive information
H
hongming 已提交
700 701
	}

H
hongming 已提交
702
	conn, err := im.ldap.NewConn()
H
hongming 已提交
703 704

	if err != nil {
H
hongming 已提交
705
		klog.Errorln(err)
H
hongming 已提交
706
		return nil, err
H
hongming 已提交
707 708
	}

H
hongming 已提交
709
	err = conn.Add(createRequest)
H
hongming 已提交
710 711

	if err != nil {
H
hongming 已提交
712 713
		klog.Errorln(err)
		return nil, err
H
hongming 已提交
714 715
	}

H
hongming 已提交
716
	return user, nil
H
hongming 已提交
717 718
}

H
hongming 已提交
719
func (im *imOperator) UpdateUser(user *User) (*User, error) {
H
hongming 已提交
720

H
hongming 已提交
721
	client, err := clientset.ClientSets().Ldap()
H
hongming 已提交
722
	if err != nil {
H
hongming 已提交
723
		return nil, err
H
hongming 已提交
724
	}
H
hongming 已提交
725
	conn, err := im.ldap.NewConn()
H
hongming 已提交
726 727 728 729
	if err != nil {
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
730

H
hongming 已提交
731
	dn := fmt.Sprintf("uid=%s,%s", user.Username, im.ldap.UserSearchBase())
H
hongming 已提交
732 733
	userModifyRequest := ldap.NewModifyRequest(dn, nil)
	if user.Email != "" {
H
hongming 已提交
734
		userSearchRequest := ldap.NewSearchRequest(
H
hongming 已提交
735
			im.ldap.UserSearchBase(),
H
hongming 已提交
736 737 738 739 740
			ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
			fmt.Sprintf("(&(objectClass=inetOrgPerson)(mail=%s))", user.Email),
			[]string{"uid", "mail"},
			nil,
		)
H
hongming 已提交
741
		result, err := conn.Search(userSearchRequest)
H
hongming 已提交
742
		if err != nil {
743
			klog.Error(err)
H
hongming 已提交
744 745 746 747
			return nil, err
		}
		if len(result.Entries) > 1 {
			err = ldap.NewError(ldap.ErrorDebugging, fmt.Errorf("email is duplicated: %s", user.Email))
748
			klog.Error(err)
H
hongming 已提交
749 750 751 752
			return nil, err
		}
		if len(result.Entries) == 1 && result.Entries[0].GetAttributeValue("uid") != user.Username {
			err = ldap.NewError(ldap.LDAPResultEntryAlreadyExists, fmt.Errorf("email is duplicated: %s", user.Email))
753
			klog.Error(err)
H
hongming 已提交
754 755
			return nil, err
		}
H
hongming 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769
		userModifyRequest.Replace("mail", []string{user.Email})
	}
	if user.Description != "" {
		userModifyRequest.Replace("description", []string{user.Description})
	}

	if user.Lang != "" {
		userModifyRequest.Replace("preferredLanguage", []string{user.Lang})
	}

	if user.Password != "" {
		userModifyRequest.Replace("userPassword", []string{user.Password})
	}

H
hongming 已提交
770
	err = conn.Modify(userModifyRequest)
H
hongming 已提交
771 772

	if err != nil {
773
		klog.Error(err)
H
hongming 已提交
774
		return nil, err
H
hongming 已提交
775 776
	}

H
hongming 已提交
777 778
	if user.ClusterRole != "" {
		err = CreateClusterRoleBinding(user.Username, user.ClusterRole)
H
hongming 已提交
779

H
hongming 已提交
780 781 782 783
		if err != nil {
			klog.Errorln(err)
			return nil, err
		}
H
hongming 已提交
784 785
	}

786 787
	// clear auth failed record
	if user.Password != "" {
788 789 790 791
		redisClient, err := clientset.ClientSets().Redis()
		if err != nil {
			return nil, err
		}
792

H
hongming 已提交
793
		records, err := im.redis.Keys(fmt.Sprintf("kubesphere:authfailed:%s:*", user.Username)).Result()
794 795

		if err == nil {
H
hongming 已提交
796
			im.redis.Del(records...)
797 798 799
		}
	}

H
hongming 已提交
800
	return GetUserInfo(user.Username)
H
hongming 已提交
801
}
H
hongming 已提交
802
func (im *imOperator) DeleteGroup(path string) error {
H
hongming 已提交
803

H
hongming 已提交
804 805 806 807
	client, err := clientset.ClientSets().Ldap()
	if err != nil {
		return err
	}
H
hongming 已提交
808
	conn, err := im.ldap.NewConn()
H
hongming 已提交
809 810 811
	if err != nil {
		return err
	}
H
hongming 已提交
812
	defer conn.Close()
H
hongming 已提交
813 814 815 816

	searchBase, cn := splitPath(path)

	groupDeleteRequest := ldap.NewDelRequest(fmt.Sprintf("cn=%s,%s", cn, searchBase), nil)
H
hongming 已提交
817
	err = conn.Del(groupDeleteRequest)
H
hongming 已提交
818 819

	if err != nil {
820
		klog.Errorln("delete user group", err)
H
hongming 已提交
821 822 823 824 825 826
		return err
	}

	return nil
}

H
hongming 已提交
827
func (im *imOperator) CreateGroup(group *models.Group) (*models.Group, error) {
H
hongming 已提交
828

H
hongming 已提交
829
	client, err := clientset.ClientSets().Ldap()
H
hongming 已提交
830 831 832
	if err != nil {
		return nil, err
	}
H
hongming 已提交
833
	conn, err := im.ldap.NewConn()
H
hongming 已提交
834 835 836 837
	if err != nil {
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
838

H
hongming 已提交
839
	maxGid, err := getMaxGid()
H
hongming 已提交
840 841

	if err != nil {
842
		klog.Errorln("get max gid", err)
H
hongming 已提交
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
		return nil, err
	}

	maxGid += 1

	if group.Path == "" {
		group.Path = group.Name
	}

	searchBase, cn := splitPath(group.Path)

	groupCreateRequest := ldap.NewAddRequest(fmt.Sprintf("cn=%s,%s", cn, searchBase), nil)
	groupCreateRequest.Attribute("objectClass", []string{"posixGroup", "top"})
	groupCreateRequest.Attribute("cn", []string{cn})
	groupCreateRequest.Attribute("gidNumber", []string{strconv.Itoa(maxGid)})

	if group.Description != "" {
		groupCreateRequest.Attribute("description", []string{group.Description})
	}

H
hongming 已提交
863 864 865
	if group.Members != nil {
		groupCreateRequest.Attribute("memberUid", group.Members)
	}
H
hongming 已提交
866

H
hongming 已提交
867
	err = conn.Add(groupCreateRequest)
H
hongming 已提交
868 869

	if err != nil {
870
		klog.Errorln("create group", err)
H
hongming 已提交
871 872 873 874 875
		return nil, err
	}

	group.Gid = strconv.Itoa(maxGid)

H
hongming 已提交
876
	return DescribeGroup(group.Path)
H
hongming 已提交
877 878
}

H
hongming 已提交
879
func (im *imOperator) UpdateGroup(group *models.Group) (*models.Group, error) {
H
hongming 已提交
880

H
hongming 已提交
881
	client, err := clientset.ClientSets().Ldap()
H
hongming 已提交
882 883 884
	if err != nil {
		return nil, err
	}
H
hongming 已提交
885
	conn, err := im.ldap.NewConn()
H
hongming 已提交
886 887 888 889
	if err != nil {
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
890

H
hongming 已提交
891
	old, err := DescribeGroup(group.Path)
H
hongming 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916

	if err != nil {
		return nil, err
	}

	searchBase, cn := splitPath(group.Path)

	groupUpdateRequest := ldap.NewModifyRequest(fmt.Sprintf("cn=%s,%s", cn, searchBase), nil)

	if old.Description == "" {
		if group.Description != "" {
			groupUpdateRequest.Add("description", []string{group.Description})
		}
	} else {
		if group.Description != "" {
			groupUpdateRequest.Replace("description", []string{group.Description})
		} else {
			groupUpdateRequest.Delete("description", []string{})
		}
	}

	if group.Members != nil {
		groupUpdateRequest.Replace("memberUid", group.Members)
	}

H
hongming 已提交
917
	err = conn.Modify(groupUpdateRequest)
H
hongming 已提交
918 919

	if err != nil {
920
		klog.Errorln("update group", err)
H
hongming 已提交
921 922 923 924 925 926
		return nil, err
	}

	return group, nil
}

H
hongming 已提交
927
func (im *imOperator) ChildList(path string) ([]models.Group, error) {
H
hongming 已提交
928

H
hongming 已提交
929
	client, err := clientset.ClientSets().Ldap()
H
hongming 已提交
930 931 932
	if err != nil {
		return nil, err
	}
H
hongming 已提交
933
	conn, err := im.ldap.NewConn()
H
hongming 已提交
934 935 936 937
	if err != nil {
		return nil, err
	}
	defer conn.Close()
H
hongming 已提交
938 939 940

	var groupSearchRequest *ldap.SearchRequest
	if path == "" {
H
hongming 已提交
941
		groupSearchRequest = ldap.NewSearchRequest(client.GroupSearchBase(),
H
hongming 已提交
942 943 944 945 946 947 948 949 950 951 952 953 954
			ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
			"(&(objectClass=posixGroup))",
			[]string{"cn", "gidNumber", "memberUid", "description"},
			nil)
	} else {
		searchBase, cn := splitPath(path)
		groupSearchRequest = ldap.NewSearchRequest(fmt.Sprintf("cn=%s,%s", cn, searchBase),
			ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
			"(&(objectClass=posixGroup))",
			[]string{"cn", "gidNumber", "memberUid", "description"},
			nil)
	}

H
hongming 已提交
955
	result, err := conn.Search(groupSearchRequest)
H
hongming 已提交
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977

	if err != nil {
		return nil, err
	}

	groups := make([]models.Group, 0)

	for _, v := range result.Entries {
		dn := v.DN
		cn := v.GetAttributeValue("cn")
		gid := v.GetAttributeValue("gidNumber")
		members := v.GetAttributeValues("memberUid")
		description := v.GetAttributeValue("description")

		group := models.Group{Path: convertDNToPath(dn), Name: cn, Gid: gid, Members: members, Description: description}

		childSearchRequest := ldap.NewSearchRequest(dn,
			ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
			"(&(objectClass=posixGroup))",
			[]string{""},
			nil)

H
hongming 已提交
978
		result, err = conn.Search(childSearchRequest)
H
hongming 已提交
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998

		if err != nil {
			return nil, err
		}

		childGroups := make([]string, 0)

		for _, v := range result.Entries {
			child := convertDNToPath(v.DN)
			childGroups = append(childGroups, child)
		}

		group.ChildGroups = childGroups

		groups = append(groups, group)
	}

	return groups, nil
}

H
hongming 已提交
999
func (im *imOperator) DescribeGroup(path string) (*models.Group, error) {
H
hongming 已提交
1000
	client, err := clientset.ClientSets().Ldap()
H
hongming 已提交
1001 1002 1003
	if err != nil {
		return nil, err
	}
H
hongming 已提交
1004
	conn, err := im.ldap.NewConn()
H
hongming 已提交
1005 1006 1007 1008 1009 1010
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	searchBase, cn := splitPath(path)
H
hongming 已提交
1011

H
hongming 已提交
1012 1013 1014 1015 1016 1017
	groupSearchRequest := ldap.NewSearchRequest(searchBase,
		ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
		fmt.Sprintf("(&(objectClass=posixGroup)(cn=%s))", cn),
		[]string{"cn", "gidNumber", "memberUid", "description"},
		nil)

H
hongming 已提交
1018
	result, err := conn.Search(groupSearchRequest)
H
hongming 已提交
1019 1020

	if err != nil {
1021
		klog.Errorln("search group", err)
H
hongming 已提交
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
		return nil, err
	}

	if len(result.Entries) != 1 {
		return nil, ldap.NewError(ldap.LDAPResultNoSuchObject, fmt.Errorf("group %s does not exist", path))
	}

	dn := result.Entries[0].DN
	cn = result.Entries[0].GetAttributeValue("cn")
	gid := result.Entries[0].GetAttributeValue("gidNumber")
	members := result.Entries[0].GetAttributeValues("memberUid")
	description := result.Entries[0].GetAttributeValue("description")

	group := models.Group{Path: convertDNToPath(dn), Name: cn, Gid: gid, Members: members, Description: description}

	childGroups := make([]string, 0)

	group.ChildGroups = childGroups

H
hongming 已提交
1041 1042 1043 1044
	return &group, nil

}

H
hongming 已提交
1045
func (im *imOperator) WorkspaceUsersTotalCount(workspace string) (int, error) {
H
hongming 已提交
1046 1047 1048 1049 1050
	workspaceRoleBindings, err := GetWorkspaceRoleBindings(workspace)

	if err != nil {
		return 0, err
	}
H
hongming 已提交
1051

H
hongming 已提交
1052
	users := make([]string, 0)
H
hongming 已提交
1053

H
hongming 已提交
1054 1055
	for _, roleBinding := range workspaceRoleBindings {
		for _, subject := range roleBinding.Subjects {
1056
			if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
H
hongming 已提交
1057 1058
				users = append(users, subject.Name)
			}
H
hongming 已提交
1059 1060 1061
		}
	}

H
hongming 已提交
1062 1063 1064
	return len(users), nil
}

H
hongming 已提交
1065
func (im *imOperator) ListWorkspaceUsers(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
H
hongming 已提交
1066 1067 1068 1069 1070 1071 1072

	workspaceRoleBindings, err := GetWorkspaceRoleBindings(workspace)

	if err != nil {
		return nil, err
	}

H
hongming 已提交
1073
	users := make([]*User, 0)
H
hongming 已提交
1074

H
hongming 已提交
1075 1076
	for _, roleBinding := range workspaceRoleBindings {
		for _, subject := range roleBinding.Subjects {
1077
			if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
H
hongming 已提交
1078
				user, err := GetUserInfo(subject.Name)
H
hongming 已提交
1079 1080 1081 1082 1083
				if err != nil {
					return nil, err
				}
				prefix := fmt.Sprintf("workspace:%s:", workspace)
				user.WorkspaceRole = fmt.Sprintf("workspace-%s", strings.TrimPrefix(roleBinding.Name, prefix))
H
hongming 已提交
1084 1085 1086
				if matchConditions(conditions, user) {
					users = append(users, user)
				}
H
hongming 已提交
1087
			}
H
hongming 已提交
1088 1089 1090
		}
	}

H
hongming 已提交
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
	// order & reverse
	sort.Slice(users, func(i, j int) bool {
		if reverse {
			tmp := i
			i = j
			j = tmp
		}
		switch orderBy {
		default:
			fallthrough
		case "name":
			return strings.Compare(users[i].Username, users[j].Username) <= 0
		}
	})

	result := make([]interface{}, 0)

	for i, d := range users {
		if i >= offset && (limit == -1 || len(result) < limit) {
			result = append(result, d)
		}
	}
H
hongming 已提交
1113

H
hongming 已提交
1114
	return &models.PageableResponse{Items: result, TotalCount: len(users)}, nil
H
hongming 已提交
1115
}
H
hongming 已提交
1116

H
hongming 已提交
1117 1118 1119 1120 1121
func (im *imOperator) uidNumberNext() int {
	return 0
}

func matchConditions(conditions *params.Conditions, user *User) bool {
H
hongming 已提交
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
	for k, v := range conditions.Match {
		switch k {
		case "keyword":
			if !strings.Contains(user.Username, v) &&
				!strings.Contains(user.Email, v) &&
				!strings.Contains(user.Description, v) {
				return false
			}
		case "name":
			names := strings.Split(v, "|")
			if !sliceutil.HasString(names, user.Username) {
				return false
			}
		case "email":
			email := strings.Split(v, "|")
			if !sliceutil.HasString(email, user.Email) {
				return false
			}
		case "role":
			if user.WorkspaceRole != v {
				return false
			}
		}
	}
	return true
}
H
hongming 已提交
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157

type User struct {
	Username    string    `json:"username"`
	Email       string    `json:"email"`
	Lang        string    `json:"lang,omitempty"`
	Description string    `json:"description"`
	CreateTime  time.Time `json:"create_time"`
	Groups      []string  `json:"groups,omitempty"`
	Password    string    `json:"password,omitempty"`
}