Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-03-22 15:57:29 +08:00
parent b9bdcd824c
commit cae7843832
13 changed files with 228 additions and 103 deletions

View File

@@ -3,6 +3,7 @@ package token
import ( import (
"fmt" "fmt"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/errors"
"time" "time"
) )
@@ -14,7 +15,7 @@ var errInvalidToken = errors.New("invalid token")
type claims struct { type claims struct {
Username string `json:"username"` Username string `json:"username"`
UID string `json:"uid"` UID string `json:"uid"`
Groups []string `json:"groups"` Email string `json:"email"`
// Currently, we are not using any field in jwt.StandardClaims // Currently, we are not using any field in jwt.StandardClaims
jwt.StandardClaims jwt.StandardClaims
} }
@@ -37,14 +38,14 @@ func (s *jwtTokenIssuer) Verify(tokenString string) (User, error) {
return nil, err 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) { func (s *jwtTokenIssuer) IssueTo(user User) (string, error) {
clm := &claims{ clm := &claims{
Username: user.GetName(), Username: user.GetName(),
UID: user.GetUID(), UID: user.GetUID(),
Groups: user.GetGroups(), Email: user.GetEmail(),
StandardClaims: jwt.StandardClaims{ StandardClaims: jwt.StandardClaims{
IssuedAt: time.Now().Unix(), IssuedAt: time.Now().Unix(),
Issuer: s.name, Issuer: s.name,

View File

@@ -2,6 +2,7 @@ package token
import ( import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"kubesphere.io/kubesphere/pkg/api/iam"
"testing" "testing"
) )
@@ -12,19 +13,22 @@ func TestJwtTokenIssuer(t *testing.T) {
description string description string
name string name string
uid string uid string
email string
}{ }{
{ {
name: "admin", name: "admin",
uid: "b8be6edd-2c92-4535-9b2a-df6326474458", uid: "b8be6edd-2c92-4535-9b2a-df6326474458",
email: "admin@kubesphere.io",
}, },
{ {
name: "bar", name: "bar",
uid: "b8be6edd-2c92-4535-9b2a-df6326474452", uid: "b8be6edd-2c92-4535-9b2a-df6326474452",
email: "bar@kubesphere.io",
}, },
} }
for _, testCase := range testCases { for _, testCase := range testCases {
user := &AuthUser{ user := &iam.User{
Name: testCase.name, Name: testCase.name,
UID: testCase.uid, UID: testCase.uid,
} }

View File

@@ -7,24 +7,6 @@ type User interface {
// UID // UID
GetUID() string GetUID() string
// Groups // Email
GetGroups() []string GetEmail() 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
} }

View File

@@ -6,30 +6,30 @@ import (
) )
type User struct { type User struct {
Username string `json:"username"` Name string `json:"username"`
UID string `json:"uid"` UID string `json:"uid"`
Email string `json:"email"` Email string `json:"email"`
Lang string `json:"lang,omitempty"` Lang string `json:"lang,omitempty"`
Description string `json:"description"` Description string `json:"description"`
CreateTime time.Time `json:"create_time"` CreateTime time.Time `json:"createTime"`
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
} }
func (u *User) GetName() string { func (u *User) GetName() string {
return u.Username return u.Name
} }
func (u *User) GetUID() string { func (u *User) GetUID() string {
return u.UID return u.UID
} }
func (u *User) GetGroups() []string { func (u *User) GetEmail() string {
return u.Groups return u.Email
} }
func (u *User) Validate() error { func (u *User) Validate() error {
if u.Username == "" { if u.Name == "" {
return errors.New("username can not be empty") return errors.New("username can not be empty")
} }

View File

@@ -29,20 +29,21 @@ type opaAuthorizer struct {
am am.AccessManagementInterface am am.AccessManagementInterface
} }
// Make decision by request attributes
func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { 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()) platformRole, err := o.am.GetPlatformRole(attr.GetUser().GetName())
if err != nil { if err != nil {
return authorizer.DecisionDeny, "", err return authorizer.DecisionDeny, "", err
} }
// check platform role policy rules // check platform role policy rules
if a, r, e := makeDecision(platformRole, attr); a == authorizer.DecisionAllow { if authorized, reason, err = makeDecision(platformRole, attr); authorized == authorizer.DecisionAllow {
return a, r, e return authorized, reason, err
} }
// it's not in cluster resource, permission denied // it's not in cluster resource, permission denied
// TODO declare implicit cluster info in request Info
if attr.GetCluster() == "" { if attr.GetCluster() == "" {
return authorizer.DecisionDeny, "permission undefined", nil return authorizer.DecisionDeny, "permission undefined", nil
} }
@@ -78,7 +79,7 @@ func (o *opaAuthorizer) Authorize(attr authorizer.Attributes) (authorized author
} }
if attr.GetNamespace() != "" { 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 { if err != nil {
return authorizer.DecisionDeny, "", err return authorizer.DecisionDeny, "", err
} }
@@ -102,6 +103,29 @@ func makeDecision(role am.Role, a authorizer.Attributes) (authorized authorizer.
return authorizer.DecisionDeny, "", err 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. // 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)) results, err := query.Eval(context.Background(), rego.EvalInput(a))

View File

@@ -27,8 +27,29 @@ import (
) )
func TestPlatformRole(t *testing.T) { 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 { tests := []struct {
name string name string
@@ -36,7 +57,7 @@ func TestPlatformRole(t *testing.T) {
expectedDecision authorizer.Decision expectedDecision authorizer.Decision
}{ }{
{ {
name: "list nodes", name: "admin can list nodes",
request: authorizer.AttributesRecord{ request: authorizer.AttributesRecord{
User: &user.DefaultInfo{ User: &user.DefaultInfo{
Name: "admin", Name: "admin",
@@ -60,7 +81,7 @@ func TestPlatformRole(t *testing.T) {
expectedDecision: authorizer.DecisionAllow, expectedDecision: authorizer.DecisionAllow,
}, },
{ {
name: "list nodes", name: "anonymous can not list nodes",
request: authorizer.AttributesRecord{ request: authorizer.AttributesRecord{
User: &user.DefaultInfo{ User: &user.DefaultInfo{
Name: user.Anonymous, Name: user.Anonymous,
@@ -82,13 +103,54 @@ func TestPlatformRole(t *testing.T) {
Path: "/api/v1/nodes", Path: "/api/v1/nodes",
}, },
expectedDecision: authorizer.DecisionDeny, 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 { for _, test := range tests {
decision, _, err := opa.Authorize(test.request) decision, _, err := opa.Authorize(test.request)
if err != nil { if err != nil {
t.Error(err) t.Errorf("test failed: %s, %v", test.name, err)
} }
if decision != test.expectedDecision { if decision != test.expectedDecision {
t.Errorf("%s: expected decision %v, actual %+v", test.name, test.expectedDecision, decision) t.Errorf("%s: expected decision %v, actual %+v", test.name, test.expectedDecision, decision)

View File

@@ -65,7 +65,7 @@ func (h *oauthHandler) TokenReviewHandler(req *restful.Request, resp *restful.Re
Kind: auth.KindTokenReview, Kind: auth.KindTokenReview,
Status: &auth.Status{ Status: &auth.Status{
Authenticated: true, 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()},
}, },
} }

View File

@@ -36,7 +36,7 @@ type AccessManagementInterface interface {
GetPlatformRole(username string) (Role, error) GetPlatformRole(username string) (Role, error)
GetClusterRole(cluster, username string) (Role, error) GetClusterRole(cluster, username string) (Role, error)
GetWorkspaceRole(workspace, 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 { type Role interface {
@@ -73,10 +73,6 @@ func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error)
panic("implement me") panic("implement me")
} }
func (am *amOperator) GetNamespaceRole(namespace, username string) (Role, error) { func (am *amOperator) GetNamespaceRole(cluster, namespace, username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetDevOpsRole(namespace, username string) (Role, error) {
panic("implement me") panic("implement me")
} }

View File

@@ -19,55 +19,111 @@
package am package am
import ( import (
"k8s.io/apiserver/pkg/authentication/user" "encoding/json"
"fmt"
"kubesphere.io/kubesphere/pkg/simple/client/cache" "kubesphere.io/kubesphere/pkg/simple/client/cache"
) )
type fakeRole struct { type FakeRole struct {
Name string Name string
Rego string Rego string
} }
type fakeOperator struct { type FakeOperator struct {
cache cache.Interface cache cache.Interface
} }
func newFakeRole(username string) Role { func (f FakeOperator) queryFakeRole(cacheKey string) (Role, error) {
if username == user.Anonymous { data, err := f.cache.Get(cacheKey)
return &fakeRole{ if err != nil {
Name: "anonymous", if err == cache.ErrNoSuchKey {
return &FakeRole{
Name: "DenyAll",
Rego: "package authz\ndefault allow = false", Rego: "package authz\ndefault allow = false",
}, nil
} }
return nil, err
} }
return &fakeRole{ var role FakeRole
Name: "admin", err = json.Unmarshal([]byte(data), &role)
Rego: "package authz\ndefault allow = true", 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)
} }
} }
func (f fakeOperator) GetPlatformRole(username string) (Role, error) { for workspace, roles := range workspaceRoles {
return newFakeRole(username), nil for username, role := range roles {
f.saveFakeRole(workspaceRoleCacheKey(workspace, username), role)
}
} }
func (f fakeOperator) GetClusterRole(cluster, username string) (Role, error) { for cluster, nsRoles := range namespaceRoles {
return newFakeRole(username), nil for namespace, roles := range nsRoles {
for username, role := range roles {
f.saveFakeRole(namespaceRoleCacheKey(cluster, namespace, username), role)
}
}
}
} }
func (f fakeOperator) GetWorkspaceRole(workspace, username string) (Role, error) { func namespaceRoleCacheKey(cluster, namespace, username string) string {
return newFakeRole(username), nil return fmt.Sprintf("cluster.%s.namespaces.%s.roles.%s", cluster, namespace, username)
} }
func (f fakeOperator) GetNamespaceRole(namespace, username string) (Role, error) { func clusterRoleCacheKey(cluster, username string) string {
return newFakeRole(username), nil 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 fakeRole) GetName() string { func platformRoleCacheKey(username string) string {
return fmt.Sprintf("platform.roles.%s", username)
}
func (f FakeRole) GetName() string {
return f.Name return f.Name
} }
func (f fakeRole) GetRego() string { func (f FakeRole) GetRego() string {
return f.Rego return f.Rego
} }
func NewFakeAMOperator(cache cache.Interface) AccessManagementInterface { func NewFakeAMOperator(cache cache.Interface) *FakeOperator {
return &fakeOperator{cache: cache} return &FakeOperator{cache: cache}
} }

View File

@@ -75,13 +75,13 @@ func (im *imOperator) ModifyUser(user *iam.User) (*iam.User, error) {
// clear auth failed record // clear auth failed record
if user.Password != "" { if user.Password != "" {
records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Username, "*")) records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(user.Name, "*"))
if err == nil { if err == nil {
im.cacheClient.Del(records...) 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) { 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 return nil, err
} }
err = im.ldapClient.Verify(user.Username, password) err = im.ldapClient.Verify(user.Name, password)
if err != nil { if err != nil {
if err == ldap.ErrInvalidCredentials { if err == ldap.ErrInvalidCredentials {
im.cacheClient.Set(authenticationFailedKeyForUsername(username, fmt.Sprintf("%d", time.Now().UnixNano())), "", 30*time.Minute) 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. // 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 { if !im.authenticateOptions.MultipleLogin {
// multi login not allowed, remove the previous token // multi login not allowed, remove the previous token
sessions, err := im.cacheClient.Keys(tokenKey) sessions, err := im.cacheClient.Keys(tokenKey)
@@ -136,7 +136,7 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error
return nil, err return nil, err
} }
im.logLogin(user.Username, ip, time.Now()) im.logLogin(user.Name, ip, time.Now())
return &oauth2.Token{AccessToken: issuedToken}, nil return &oauth2.Token{AccessToken: issuedToken}, nil
} }

View File

@@ -216,7 +216,7 @@ func (l *ldapInterfaceImpl) Get(name string) (*iam.User, error) {
userEntry := searchResults.Entries[0] userEntry := searchResults.Entries[0]
user := &iam.User{ user := &iam.User{
Username: userEntry.GetAttributeValue(ldapAttributeUserID), Name: userEntry.GetAttributeValue(ldapAttributeUserID),
Email: userEntry.GetAttributeValue(ldapAttributeMail), Email: userEntry.GetAttributeValue(ldapAttributeMail),
Lang: userEntry.GetAttributeValue(ldapAttributePreferredLanguage), Lang: userEntry.GetAttributeValue(ldapAttributePreferredLanguage),
Description: userEntry.GetAttributeValue(ldapAttributeDescription), 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 { 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 return ErrUserAlreadyExisted
} }
createRequest := &ldap.AddRequest{ createRequest := &ldap.AddRequest{
DN: l.dnForUsername(user.Username), DN: l.dnForUsername(user.Name),
Attributes: []ldap.Attribute{ Attributes: []ldap.Attribute{
{ {
Type: ldapAttributeObjectClass, Type: ldapAttributeObjectClass,
@@ -242,7 +242,7 @@ func (l *ldapInterfaceImpl) Create(user *iam.User) error {
}, },
{ {
Type: ldapAttributeCommonName, Type: ldapAttributeCommonName,
Vals: []string{user.Username}, Vals: []string{user.Name},
}, },
{ {
Type: ldapAttributeSerialNumber, Type: ldapAttributeSerialNumber,
@@ -254,11 +254,11 @@ func (l *ldapInterfaceImpl) Create(user *iam.User) error {
}, },
{ {
Type: ldapAttributeHomeDirectory, Type: ldapAttributeHomeDirectory,
Vals: []string{"/home/" + user.Username}, Vals: []string{"/home/" + user.Name},
}, },
{ {
Type: ldapAttributeUserID, Type: ldapAttributeUserID,
Vals: []string{user.Username}, Vals: []string{user.Name},
}, },
{ {
Type: ldapAttributeUserIDNumber, Type: ldapAttributeUserIDNumber,
@@ -322,13 +322,13 @@ func (l *ldapInterfaceImpl) Update(newUser *iam.User) error {
defer conn.Close() defer conn.Close()
// check user existed // check user existed
_, err = l.Get(newUser.Username) _, err = l.Get(newUser.Name)
if err != nil { if err != nil {
return err return err
} }
modifyRequest := &ldap.ModifyRequest{ modifyRequest := &ldap.ModifyRequest{
DN: l.dnForUsername(newUser.Username), DN: l.dnForUsername(newUser.Name),
} }
if newUser.Description != "" { if newUser.Description != "" {

View File

@@ -17,7 +17,7 @@ func NewSimpleLdap() Interface {
// initialize with a admin user // initialize with a admin user
admin := &iam.User{ admin := &iam.User{
Username: "admin", Name: "admin",
Email: "admin@kubesphere.io", Email: "admin@kubesphere.io",
Lang: "eng", Lang: "eng",
Description: "administrator", Description: "administrator",
@@ -25,21 +25,21 @@ func NewSimpleLdap() Interface {
Groups: nil, Groups: nil,
Password: "P@88w0rd", Password: "P@88w0rd",
} }
sl.store[admin.Username] = admin sl.store[admin.Name] = admin
return sl return sl
} }
func (s simpleLdap) Create(user *iam.User) error { func (s simpleLdap) Create(user *iam.User) error {
s.store[user.Username] = user s.store[user.Name] = user
return nil return nil
} }
func (s simpleLdap) Update(user *iam.User) error { func (s simpleLdap) Update(user *iam.User) error {
_, err := s.Get(user.Username) _, err := s.Get(user.Name)
if err != nil { if err != nil {
return err return err
} }
s.store[user.Username] = user s.store[user.Name] = user
return nil return nil
} }

View File

@@ -11,7 +11,7 @@ func TestSimpleLdap(t *testing.T) {
ldapClient := NewSimpleLdap() ldapClient := NewSimpleLdap()
foo := &iam.User{ foo := &iam.User{
Username: "jerry", Name: "jerry",
Email: "jerry@kubesphere.io", Email: "jerry@kubesphere.io",
Lang: "en", Lang: "en",
Description: "Jerry is kind and gentle.", Description: "Jerry is kind and gentle.",
@@ -27,7 +27,7 @@ func TestSimpleLdap(t *testing.T) {
} }
// check if user really created // check if user really created
user, err := ldapClient.Get(foo.Username) user, err := ldapClient.Get(foo.Name)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -35,7 +35,7 @@ func TestSimpleLdap(t *testing.T) {
t.Fatalf("%T differ (-got, +want): %s", user, diff) 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) { t.Run("should update user", func(t *testing.T) {
@@ -51,7 +51,7 @@ func TestSimpleLdap(t *testing.T) {
} }
// check if user really created // check if user really created
user, err := ldapClient.Get(foo.Username) user, err := ldapClient.Get(foo.Name)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -59,7 +59,7 @@ func TestSimpleLdap(t *testing.T) {
t.Fatalf("%T differ (-got, +want): %s", user, diff) 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) { t.Run("should delete user", func(t *testing.T) {
@@ -68,12 +68,12 @@ func TestSimpleLdap(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = ldapClient.Delete(foo.Username) err = ldapClient.Delete(foo.Name)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = ldapClient.Get(foo.Username) _, err = ldapClient.Get(foo.Name)
if err == nil || err != ErrUserNotExists { if err == nil || err != ErrUserNotExists {
t.Fatalf("expected ErrUserNotExists error, got %v", err) t.Fatalf("expected ErrUserNotExists error, got %v", err)
} }
@@ -85,12 +85,12 @@ func TestSimpleLdap(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
err = ldapClient.Verify(foo.Username, foo.Password) err = ldapClient.Verify(foo.Name, foo.Password)
if err != nil { if err != nil {
t.Fatalf("should pass but got an error %v", err) 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 { if err == nil || err != ErrInvalidCredentials {
t.Fatalf("expected error ErrInvalidCrenentials but got %v", err) t.Fatalf("expected error ErrInvalidCrenentials but got %v", err)
} }