@@ -3,6 +3,7 @@ package token
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"kubesphere.io/kubesphere/pkg/api/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"time"
|
||||
)
|
||||
@@ -12,9 +13,9 @@ const DefaultIssuerName = "kubesphere"
|
||||
var errInvalidToken = errors.New("invalid token")
|
||||
|
||||
type claims struct {
|
||||
Username string `json:"username"`
|
||||
UID string `json:"uid"`
|
||||
Groups []string `json:"groups"`
|
||||
Username string `json:"username"`
|
||||
UID string `json:"uid"`
|
||||
Email string `json:"email"`
|
||||
// Currently, we are not using any field in jwt.StandardClaims
|
||||
jwt.StandardClaims
|
||||
}
|
||||
@@ -37,14 +38,14 @@ func (s *jwtTokenIssuer) Verify(tokenString string) (User, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AuthUser{Name: clm.Username, UID: clm.UID, Groups: clm.Groups}, nil
|
||||
return &iam.User{Name: clm.Username, UID: clm.UID, Email: clm.Email}, nil
|
||||
}
|
||||
|
||||
func (s *jwtTokenIssuer) IssueTo(user User) (string, error) {
|
||||
clm := &claims{
|
||||
Username: user.GetName(),
|
||||
UID: user.GetUID(),
|
||||
Groups: user.GetGroups(),
|
||||
Email: user.GetEmail(),
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
IssuedAt: time.Now().Unix(),
|
||||
Issuer: s.name,
|
||||
|
||||
@@ -2,6 +2,7 @@ package token
|
||||
|
||||
import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"kubesphere.io/kubesphere/pkg/api/iam"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -12,19 +13,22 @@ func TestJwtTokenIssuer(t *testing.T) {
|
||||
description string
|
||||
name string
|
||||
uid string
|
||||
email string
|
||||
}{
|
||||
{
|
||||
name: "admin",
|
||||
uid: "b8be6edd-2c92-4535-9b2a-df6326474458",
|
||||
name: "admin",
|
||||
uid: "b8be6edd-2c92-4535-9b2a-df6326474458",
|
||||
email: "admin@kubesphere.io",
|
||||
},
|
||||
{
|
||||
name: "bar",
|
||||
uid: "b8be6edd-2c92-4535-9b2a-df6326474452",
|
||||
name: "bar",
|
||||
uid: "b8be6edd-2c92-4535-9b2a-df6326474452",
|
||||
email: "bar@kubesphere.io",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
user := &AuthUser{
|
||||
user := &iam.User{
|
||||
Name: testCase.name,
|
||||
UID: testCase.uid,
|
||||
}
|
||||
|
||||
@@ -7,24 +7,6 @@ type User interface {
|
||||
// UID
|
||||
GetUID() string
|
||||
|
||||
// Groups
|
||||
GetGroups() []string
|
||||
}
|
||||
|
||||
type AuthUser struct {
|
||||
Name string
|
||||
UID string
|
||||
Groups []string
|
||||
}
|
||||
|
||||
func (a AuthUser) GetName() string {
|
||||
return a.Name
|
||||
}
|
||||
|
||||
func (a AuthUser) GetUID() string {
|
||||
return a.UID
|
||||
}
|
||||
|
||||
func (a AuthUser) GetGroups() []string {
|
||||
return a.Groups
|
||||
// Email
|
||||
GetEmail() string
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@ import (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Name string `json:"username"`
|
||||
UID string `json:"uid"`
|
||||
Email string `json:"email"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
Description string `json:"description"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
CreateTime time.Time `json:"createTime"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
func (u *User) GetName() string {
|
||||
return u.Username
|
||||
return u.Name
|
||||
}
|
||||
|
||||
func (u *User) GetUID() string {
|
||||
return u.UID
|
||||
}
|
||||
|
||||
func (u *User) GetGroups() []string {
|
||||
return u.Groups
|
||||
func (u *User) GetEmail() string {
|
||||
return u.Email
|
||||
}
|
||||
|
||||
func (u *User) Validate() error {
|
||||
if u.Username == "" {
|
||||
if u.Name == "" {
|
||||
return errors.New("username can not be empty")
|
||||
}
|
||||
|
||||
|
||||
@@ -29,20 +29,21 @@ type opaAuthorizer struct {
|
||||
am am.AccessManagementInterface
|
||||
}
|
||||
|
||||
// Make decision by request attributes
|
||||
func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
|
||||
// Make decisions based on the authorization policy of different levels of roles
|
||||
platformRole, err := o.am.GetPlatformRole(attr.GetUser().GetName())
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "", err
|
||||
}
|
||||
|
||||
// check platform role policy rules
|
||||
if a, r, e := makeDecision(platformRole, attr); a == authorizer.DecisionAllow {
|
||||
return a, r, e
|
||||
if authorized, reason, err = makeDecision(platformRole, attr); authorized == authorizer.DecisionAllow {
|
||||
return authorized, reason, err
|
||||
}
|
||||
|
||||
// it's not in cluster resource, permission denied
|
||||
// TODO declare implicit cluster info in request Info
|
||||
if attr.GetCluster() == "" {
|
||||
return authorizer.DecisionDeny, "permission undefined", nil
|
||||
}
|
||||
@@ -78,7 +79,7 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author
|
||||
}
|
||||
|
||||
if attr.GetNamespace() != "" {
|
||||
namespaceRole, err := o.am.GetNamespaceRole(attr.GetNamespace(), attr.GetUser().GetName())
|
||||
namespaceRole, err := o.am.GetNamespaceRole(attr.GetCluster(), attr.GetNamespace(), attr.GetUser().GetName())
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "", err
|
||||
}
|
||||
@@ -102,6 +103,29 @@ func makeDecision(role am.Role, a authorizer.Attributes) (authorized authorizer.
|
||||
return authorizer.DecisionDeny, "", err
|
||||
}
|
||||
|
||||
// data example
|
||||
//{
|
||||
// "User": {
|
||||
// "Name": "admin",
|
||||
// "UID": "0",
|
||||
// "Groups": [
|
||||
// "admin"
|
||||
// ],
|
||||
// "Extra": null
|
||||
// },
|
||||
// "Verb": "list",
|
||||
// "Cluster": "cluster1",
|
||||
// "Workspace": "",
|
||||
// "Namespace": "",
|
||||
// "APIGroup": "",
|
||||
// "APIVersion": "v1",
|
||||
// "Resource": "nodes",
|
||||
// "Subresource": "",
|
||||
// "Name": "",
|
||||
// "KubernetesRequest": true,
|
||||
// "ResourceRequest": true,
|
||||
// "Path": "/api/v1/nodes"
|
||||
//}
|
||||
// The policy decision is contained in the results returned by the Eval() call. You can inspect the decision and handle it accordingly.
|
||||
results, err := query.Eval(context.Background(), rego.EvalInput(a))
|
||||
|
||||
|
||||
@@ -27,8 +27,29 @@ import (
|
||||
)
|
||||
|
||||
func TestPlatformRole(t *testing.T) {
|
||||
platformRoles := map[string]am.FakeRole{"admin": {
|
||||
Name: "admin",
|
||||
Rego: "package authz\ndefault allow = true",
|
||||
}, "anonymous": {
|
||||
Name: "anonymous",
|
||||
Rego: "package authz\ndefault allow = false",
|
||||
}, "tom": {
|
||||
Name: "tom",
|
||||
Rego: `package authz
|
||||
default allow = false
|
||||
allow {
|
||||
resources_in_cluster1
|
||||
}
|
||||
resources_in_cluster1 {
|
||||
input.Cluster == "cluster1"
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
opa := NewOPAAuthorizer(am.NewFakeAMOperator(cache.NewSimpleCache()))
|
||||
operator := am.NewFakeAMOperator(cache.NewSimpleCache())
|
||||
operator.Prepare(platformRoles, nil, nil, nil)
|
||||
|
||||
opa := NewOPAAuthorizer(operator)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -36,7 +57,7 @@ func TestPlatformRole(t *testing.T) {
|
||||
expectedDecision authorizer.Decision
|
||||
}{
|
||||
{
|
||||
name: "list nodes",
|
||||
name: "admin can list nodes",
|
||||
request: authorizer.AttributesRecord{
|
||||
User: &user.DefaultInfo{
|
||||
Name: "admin",
|
||||
@@ -60,7 +81,7 @@ func TestPlatformRole(t *testing.T) {
|
||||
expectedDecision: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "list nodes",
|
||||
name: "anonymous can not list nodes",
|
||||
request: authorizer.AttributesRecord{
|
||||
User: &user.DefaultInfo{
|
||||
Name: user.Anonymous,
|
||||
@@ -82,13 +103,54 @@ func TestPlatformRole(t *testing.T) {
|
||||
Path: "/api/v1/nodes",
|
||||
},
|
||||
expectedDecision: authorizer.DecisionDeny,
|
||||
}, {
|
||||
name: "tom can list nodes in cluster1",
|
||||
request: authorizer.AttributesRecord{
|
||||
User: &user.DefaultInfo{
|
||||
Name: "tom",
|
||||
},
|
||||
Verb: "list",
|
||||
Cluster: "cluster1",
|
||||
Workspace: "",
|
||||
Namespace: "",
|
||||
APIGroup: "",
|
||||
APIVersion: "v1",
|
||||
Resource: "nodes",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
KubernetesRequest: true,
|
||||
ResourceRequest: true,
|
||||
Path: "/api/v1/clusters/cluster1/nodes",
|
||||
},
|
||||
expectedDecision: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "tom can not list nodes in cluster2",
|
||||
request: authorizer.AttributesRecord{
|
||||
User: &user.DefaultInfo{
|
||||
Name: "tom",
|
||||
},
|
||||
Verb: "list",
|
||||
Cluster: "cluster2",
|
||||
Workspace: "",
|
||||
Namespace: "",
|
||||
APIGroup: "",
|
||||
APIVersion: "v1",
|
||||
Resource: "nodes",
|
||||
Subresource: "",
|
||||
Name: "",
|
||||
KubernetesRequest: true,
|
||||
ResourceRequest: true,
|
||||
Path: "/api/v1/clusters/cluster2/nodes",
|
||||
},
|
||||
expectedDecision: authorizer.DecisionDeny,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
decision, _, err := opa.Authorize(test.request)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Errorf("test failed: %s, %v", test.name, err)
|
||||
}
|
||||
if decision != test.expectedDecision {
|
||||
t.Errorf("%s: expected decision %v, actual %+v", test.name, test.expectedDecision, decision)
|
||||
|
||||
@@ -65,7 +65,7 @@ func (h *oauthHandler) TokenReviewHandler(req *restful.Request, resp *restful.Re
|
||||
Kind: auth.KindTokenReview,
|
||||
Status: &auth.Status{
|
||||
Authenticated: true,
|
||||
User: map[string]interface{}{"username": user.GetName(), "uid": user.GetUID(), "groups": user.GetGroups()},
|
||||
User: map[string]interface{}{"username": user.GetName(), "uid": user.GetUID()},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ type AccessManagementInterface interface {
|
||||
GetPlatformRole(username string) (Role, error)
|
||||
GetClusterRole(cluster, username string) (Role, error)
|
||||
GetWorkspaceRole(workspace, username string) (Role, error)
|
||||
GetNamespaceRole(namespace, username string) (Role, error)
|
||||
GetNamespaceRole(cluster, namespace, username string) (Role, error)
|
||||
}
|
||||
|
||||
type Role interface {
|
||||
@@ -73,10 +73,6 @@ func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error)
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetNamespaceRole(namespace, username string) (Role, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetDevOpsRole(namespace, username string) (Role, error) {
|
||||
func (am *amOperator) GetNamespaceRole(cluster, namespace, username string) (Role, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -19,55 +19,111 @@
|
||||
package am
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
)
|
||||
|
||||
type fakeRole struct {
|
||||
type FakeRole struct {
|
||||
Name string
|
||||
Rego string
|
||||
}
|
||||
type fakeOperator struct {
|
||||
type FakeOperator struct {
|
||||
cache cache.Interface
|
||||
}
|
||||
|
||||
func newFakeRole(username string) Role {
|
||||
if username == user.Anonymous {
|
||||
return &fakeRole{
|
||||
Name: "anonymous",
|
||||
Rego: "package authz\ndefault allow = false",
|
||||
func (f FakeOperator) queryFakeRole(cacheKey string) (Role, error) {
|
||||
data, err := f.cache.Get(cacheKey)
|
||||
if err != nil {
|
||||
if err == cache.ErrNoSuchKey {
|
||||
return &FakeRole{
|
||||
Name: "DenyAll",
|
||||
Rego: "package authz\ndefault allow = false",
|
||||
}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
var role FakeRole
|
||||
err = json.Unmarshal([]byte(data), &role)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func (f FakeOperator) saveFakeRole(cacheKey string, role FakeRole) error {
|
||||
data, err := json.Marshal(role)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.cache.Set(cacheKey, string(data), 0)
|
||||
}
|
||||
|
||||
func (f FakeOperator) GetPlatformRole(username string) (Role, error) {
|
||||
return f.queryFakeRole(platformRoleCacheKey(username))
|
||||
}
|
||||
|
||||
func (f FakeOperator) GetClusterRole(cluster, username string) (Role, error) {
|
||||
return f.queryFakeRole(clusterRoleCacheKey(cluster, username))
|
||||
}
|
||||
|
||||
func (f FakeOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
|
||||
return f.queryFakeRole(workspaceRoleCacheKey(workspace, username))
|
||||
}
|
||||
|
||||
func (f FakeOperator) GetNamespaceRole(cluster, namespace, username string) (Role, error) {
|
||||
return f.queryFakeRole(namespaceRoleCacheKey(cluster, namespace, username))
|
||||
}
|
||||
|
||||
func (f FakeOperator) Prepare(platformRoles map[string]FakeRole, clusterRoles map[string]map[string]FakeRole, workspaceRoles map[string]map[string]FakeRole, namespaceRoles map[string]map[string]map[string]FakeRole) {
|
||||
|
||||
for username, role := range platformRoles {
|
||||
f.saveFakeRole(platformRoleCacheKey(username), role)
|
||||
}
|
||||
for cluster, roles := range clusterRoles {
|
||||
for username, role := range roles {
|
||||
f.saveFakeRole(clusterRoleCacheKey(cluster, username), role)
|
||||
}
|
||||
}
|
||||
return &fakeRole{
|
||||
Name: "admin",
|
||||
Rego: "package authz\ndefault allow = true",
|
||||
|
||||
for workspace, roles := range workspaceRoles {
|
||||
for username, role := range roles {
|
||||
f.saveFakeRole(workspaceRoleCacheKey(workspace, username), role)
|
||||
}
|
||||
}
|
||||
|
||||
for cluster, nsRoles := range namespaceRoles {
|
||||
for namespace, roles := range nsRoles {
|
||||
for username, role := range roles {
|
||||
f.saveFakeRole(namespaceRoleCacheKey(cluster, namespace, username), role)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f fakeOperator) GetPlatformRole(username string) (Role, error) {
|
||||
return newFakeRole(username), nil
|
||||
func namespaceRoleCacheKey(cluster, namespace, username string) string {
|
||||
return fmt.Sprintf("cluster.%s.namespaces.%s.roles.%s", cluster, namespace, username)
|
||||
}
|
||||
|
||||
func (f fakeOperator) GetClusterRole(cluster, username string) (Role, error) {
|
||||
return newFakeRole(username), nil
|
||||
func clusterRoleCacheKey(cluster, username string) string {
|
||||
return fmt.Sprintf("cluster.%s.roles.%s", cluster, username)
|
||||
}
|
||||
func workspaceRoleCacheKey(workspace, username string) string {
|
||||
return fmt.Sprintf("workspace.%s.roles.%s", workspace, username)
|
||||
}
|
||||
|
||||
func (f fakeOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
|
||||
return newFakeRole(username), nil
|
||||
func platformRoleCacheKey(username string) string {
|
||||
return fmt.Sprintf("platform.roles.%s", username)
|
||||
}
|
||||
|
||||
func (f fakeOperator) GetNamespaceRole(namespace, username string) (Role, error) {
|
||||
return newFakeRole(username), nil
|
||||
}
|
||||
|
||||
func (f fakeRole) GetName() string {
|
||||
func (f FakeRole) GetName() string {
|
||||
return f.Name
|
||||
}
|
||||
|
||||
func (f fakeRole) GetRego() string {
|
||||
func (f FakeRole) GetRego() string {
|
||||
return f.Rego
|
||||
}
|
||||
|
||||
func NewFakeAMOperator(cache cache.Interface) AccessManagementInterface {
|
||||
return &fakeOperator{cache: cache}
|
||||
func NewFakeAMOperator(cache cache.Interface) *FakeOperator {
|
||||
return &FakeOperator{cache: cache}
|
||||
}
|
||||
|
||||
@@ -75,13 +75,13 @@ func (im *imOperator) ModifyUser(user *iam.User) (*iam.User, error) {
|
||||
|
||||
// clear auth failed record
|
||||
if user.Password != "" {
|
||||
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Username, "*"))
|
||||
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Name, "*"))
|
||||
if err == nil {
|
||||
im.cacheClient.Del(records...)
|
||||
}
|
||||
}
|
||||
|
||||
return im.ldapClient.Get(user.Username)
|
||||
return im.ldapClient.Get(user.Name)
|
||||
}
|
||||
|
||||
func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error) {
|
||||
@@ -100,7 +100,7 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = im.ldapClient.Verify(user.Username, password)
|
||||
err = im.ldapClient.Verify(user.Name, password)
|
||||
if err != nil {
|
||||
if err == ldap.ErrInvalidCredentials {
|
||||
im.cacheClient.Set(authenticationFailedKeyForUsername(username, fmt.Sprintf("%d", time.Now().UnixNano())), "", 30*time.Minute)
|
||||
@@ -114,7 +114,7 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
|
||||
}
|
||||
|
||||
// TODO: I think we should come up with a better strategy to prevent multiple login.
|
||||
tokenKey := tokenKeyForUsername(user.Username, issuedToken)
|
||||
tokenKey := tokenKeyForUsername(user.Name, issuedToken)
|
||||
if !im.authenticateOptions.MultipleLogin {
|
||||
// multi login not allowed, remove the previous token
|
||||
sessions, err := im.cacheClient.Keys(tokenKey)
|
||||
@@ -136,7 +136,7 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
im.logLogin(user.Username, ip, time.Now())
|
||||
im.logLogin(user.Name, ip, time.Now())
|
||||
|
||||
return &oauth2.Token{AccessToken: issuedToken}, nil
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ func (l *ldapInterfaceImpl) Get(name string) (*iam.User, error) {
|
||||
userEntry := searchResults.Entries[0]
|
||||
|
||||
user := &iam.User{
|
||||
Username: userEntry.GetAttributeValue(ldapAttributeUserID),
|
||||
Name: userEntry.GetAttributeValue(ldapAttributeUserID),
|
||||
Email: userEntry.GetAttributeValue(ldapAttributeMail),
|
||||
Lang: userEntry.GetAttributeValue(ldapAttributePreferredLanguage),
|
||||
Description: userEntry.GetAttributeValue(ldapAttributeDescription),
|
||||
@@ -229,12 +229,12 @@ func (l *ldapInterfaceImpl) Get(name string) (*iam.User, error) {
|
||||
}
|
||||
|
||||
func (l *ldapInterfaceImpl) Create(user *iam.User) error {
|
||||
if _, err := l.Get(user.Username); err != nil {
|
||||
if _, err := l.Get(user.Name); err != nil {
|
||||
return ErrUserAlreadyExisted
|
||||
}
|
||||
|
||||
createRequest := &ldap.AddRequest{
|
||||
DN: l.dnForUsername(user.Username),
|
||||
DN: l.dnForUsername(user.Name),
|
||||
Attributes: []ldap.Attribute{
|
||||
{
|
||||
Type: ldapAttributeObjectClass,
|
||||
@@ -242,7 +242,7 @@ func (l *ldapInterfaceImpl) Create(user *iam.User) error {
|
||||
},
|
||||
{
|
||||
Type: ldapAttributeCommonName,
|
||||
Vals: []string{user.Username},
|
||||
Vals: []string{user.Name},
|
||||
},
|
||||
{
|
||||
Type: ldapAttributeSerialNumber,
|
||||
@@ -254,11 +254,11 @@ func (l *ldapInterfaceImpl) Create(user *iam.User) error {
|
||||
},
|
||||
{
|
||||
Type: ldapAttributeHomeDirectory,
|
||||
Vals: []string{"/home/" + user.Username},
|
||||
Vals: []string{"/home/" + user.Name},
|
||||
},
|
||||
{
|
||||
Type: ldapAttributeUserID,
|
||||
Vals: []string{user.Username},
|
||||
Vals: []string{user.Name},
|
||||
},
|
||||
{
|
||||
Type: ldapAttributeUserIDNumber,
|
||||
@@ -322,13 +322,13 @@ func (l *ldapInterfaceImpl) Update(newUser *iam.User) error {
|
||||
defer conn.Close()
|
||||
|
||||
// check user existed
|
||||
_, err = l.Get(newUser.Username)
|
||||
_, err = l.Get(newUser.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
modifyRequest := &ldap.ModifyRequest{
|
||||
DN: l.dnForUsername(newUser.Username),
|
||||
DN: l.dnForUsername(newUser.Name),
|
||||
}
|
||||
|
||||
if newUser.Description != "" {
|
||||
|
||||
@@ -17,7 +17,7 @@ func NewSimpleLdap() Interface {
|
||||
|
||||
// initialize with a admin user
|
||||
admin := &iam.User{
|
||||
Username: "admin",
|
||||
Name: "admin",
|
||||
Email: "admin@kubesphere.io",
|
||||
Lang: "eng",
|
||||
Description: "administrator",
|
||||
@@ -25,21 +25,21 @@ func NewSimpleLdap() Interface {
|
||||
Groups: nil,
|
||||
Password: "P@88w0rd",
|
||||
}
|
||||
sl.store[admin.Username] = admin
|
||||
sl.store[admin.Name] = admin
|
||||
return sl
|
||||
}
|
||||
|
||||
func (s simpleLdap) Create(user *iam.User) error {
|
||||
s.store[user.Username] = user
|
||||
s.store[user.Name] = user
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s simpleLdap) Update(user *iam.User) error {
|
||||
_, err := s.Get(user.Username)
|
||||
_, err := s.Get(user.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.store[user.Username] = user
|
||||
s.store[user.Name] = user
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ func TestSimpleLdap(t *testing.T) {
|
||||
ldapClient := NewSimpleLdap()
|
||||
|
||||
foo := &iam.User{
|
||||
Username: "jerry",
|
||||
Name: "jerry",
|
||||
Email: "jerry@kubesphere.io",
|
||||
Lang: "en",
|
||||
Description: "Jerry is kind and gentle.",
|
||||
@@ -27,7 +27,7 @@ func TestSimpleLdap(t *testing.T) {
|
||||
}
|
||||
|
||||
// check if user really created
|
||||
user, err := ldapClient.Get(foo.Username)
|
||||
user, err := ldapClient.Get(foo.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func TestSimpleLdap(t *testing.T) {
|
||||
t.Fatalf("%T differ (-got, +want): %s", user, diff)
|
||||
}
|
||||
|
||||
_ = ldapClient.Delete(foo.Username)
|
||||
_ = ldapClient.Delete(foo.Name)
|
||||
})
|
||||
|
||||
t.Run("should update user", func(t *testing.T) {
|
||||
@@ -51,7 +51,7 @@ func TestSimpleLdap(t *testing.T) {
|
||||
}
|
||||
|
||||
// check if user really created
|
||||
user, err := ldapClient.Get(foo.Username)
|
||||
user, err := ldapClient.Get(foo.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func TestSimpleLdap(t *testing.T) {
|
||||
t.Fatalf("%T differ (-got, +want): %s", user, diff)
|
||||
}
|
||||
|
||||
_ = ldapClient.Delete(foo.Username)
|
||||
_ = ldapClient.Delete(foo.Name)
|
||||
})
|
||||
|
||||
t.Run("should delete user", func(t *testing.T) {
|
||||
@@ -68,12 +68,12 @@ func TestSimpleLdap(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ldapClient.Delete(foo.Username)
|
||||
err = ldapClient.Delete(foo.Name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = ldapClient.Get(foo.Username)
|
||||
_, err = ldapClient.Get(foo.Name)
|
||||
if err == nil || err != ErrUserNotExists {
|
||||
t.Fatalf("expected ErrUserNotExists error, got %v", err)
|
||||
}
|
||||
@@ -85,12 +85,12 @@ func TestSimpleLdap(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ldapClient.Verify(foo.Username, foo.Password)
|
||||
err = ldapClient.Verify(foo.Name, foo.Password)
|
||||
if err != nil {
|
||||
t.Fatalf("should pass but got an error %v", err)
|
||||
}
|
||||
|
||||
err = ldapClient.Verify(foo.Username, "gibberish")
|
||||
err = ldapClient.Verify(foo.Name, "gibberish")
|
||||
if err == nil || err != ErrInvalidCredentials {
|
||||
t.Fatalf("expected error ErrInvalidCrenentials but got %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user