@@ -37,6 +37,12 @@ const (
|
||||
ResourceKindWorkspaceRole = "WorkspaceRole"
|
||||
ResourcesSingularWorkspaceRole = "workspacerole"
|
||||
ResourcesPluralWorkspaceRole = "workspaceroles"
|
||||
ResourceKindClusterRole = "ClusterRole"
|
||||
ResourcesSingularClusterRole = "clusterrole"
|
||||
ResourcesPluralClusterRole = "clusterroles"
|
||||
ResourceKindRole = "Role"
|
||||
ResourcesSingularRole = "role"
|
||||
ResourcesPluralRole = "roles"
|
||||
RegoOverrideAnnotation = "iam.kubesphere.io/rego-override"
|
||||
GlobalScope = "Global"
|
||||
ClusterScope = "Cluster"
|
||||
|
||||
@@ -11,13 +11,18 @@ import (
|
||||
unionauth "k8s.io/apiserver/pkg/authentication/request/union"
|
||||
"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
|
||||
"k8s.io/klog"
|
||||
clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/basic"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/jwttoken"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/request/anonymous"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/request/basictoken"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/request/bearertoken"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authentication/token"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory"
|
||||
authorizationoptions "kubesphere.io/kubesphere/pkg/apiserver/authorization/options"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/authorization/path"
|
||||
unionauthorizer "kubesphere.io/kubesphere/pkg/apiserver/authorization/union"
|
||||
apiserverconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
|
||||
@@ -27,7 +32,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
configv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/config/v1alpha2"
|
||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/devops/v1alpha2"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
|
||||
iamapi "kubesphere.io/kubesphere/pkg/kapis/iam/v1alpha2"
|
||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/logging/v1alpha2"
|
||||
monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3"
|
||||
networkv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/network/v1alpha2"
|
||||
@@ -118,7 +123,6 @@ func (s *APIServer) PrepareRun() error {
|
||||
s.container.Filter(logRequestAndResponse)
|
||||
s.container.Router(restful.CurlyRouter{})
|
||||
s.container.RecoverHandler(func(panicReason interface{}, httpWriter http.ResponseWriter) {
|
||||
klog.Error(panicReason)
|
||||
logStackOnRecover(panicReason, httpWriter)
|
||||
})
|
||||
|
||||
@@ -144,7 +148,7 @@ func (s *APIServer) installKubeSphereAPIs() {
|
||||
urlruntime.Must(networkv1alpha2.AddToContainer(s.container, s.Config.NetworkOptions.WeaveScopeHost))
|
||||
urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes()))
|
||||
urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.InformerFactory))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory))
|
||||
urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config()))
|
||||
urlruntime.Must(iamapi.AddToContainer(s.container, im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory),
|
||||
am.NewAMOperator(s.InformerFactory),
|
||||
@@ -189,7 +193,6 @@ func (s *APIServer) buildHandlerChain() {
|
||||
{Group: iamv1alpha2.SchemeGroupVersion.Group, Resource: iamv1alpha2.ResourcesPluralGlobalRoleBinding},
|
||||
{Group: tenantv1alpha1.SchemeGroupVersion.Group, Resource: tenantv1alpha1.ResourcePluralWorkspace},
|
||||
{Group: clusterv1alpha1.SchemeGroupVersion.Group, Resource: clusterv1alpha1.ResourcesPluralCluster},
|
||||
{Group: clusterv1alpha1.SchemeGroupVersion.Group, Resource: clusterv1alpha1.ResourcesPluralAgent},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/spf13/viper"
|
||||
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||
authorizationoptions "kubesphere.io/kubesphere/pkg/apiserver/authorization/options"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/cache"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/multicluster"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/network"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/notification"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
@@ -58,20 +60,20 @@ const (
|
||||
|
||||
// Config defines everything needed for apiserver to deal with external services
|
||||
type Config struct {
|
||||
DevopsOptions *jenkins.Options `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
|
||||
SonarQubeOptions *sonarqube.Options `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
|
||||
KubernetesOptions *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
|
||||
ServiceMeshOptions *servicemesh.Options `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
|
||||
NetworkOptions *network.Options `json:"network,omitempty" yaml:"network,omitempty" mapstructure:"network"`
|
||||
LdapOptions *ldap.Options `json:"ldap,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
|
||||
RedisOptions *cache.Options `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
|
||||
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
|
||||
OpenPitrixOptions *openpitrix.Options `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
|
||||
MonitoringOptions *prometheus.Options `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
|
||||
LoggingOptions *elasticsearch.Options `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
|
||||
AuthenticationOptions *authoptions.AuthenticationOptions `json:"authentication,omitempty" yaml:"authentication,omitempty" mapstructure:"authentication"`
|
||||
DevopsOptions *jenkins.Options `json:"devops,omitempty" yaml:"devops,omitempty" mapstructure:"devops"`
|
||||
SonarQubeOptions *sonarqube.Options `json:"sonarqube,omitempty" yaml:"sonarQube,omitempty" mapstructure:"sonarqube"`
|
||||
KubernetesOptions *k8s.KubernetesOptions `json:"kubernetes,omitempty" yaml:"kubernetes,omitempty" mapstructure:"kubernetes"`
|
||||
ServiceMeshOptions *servicemesh.Options `json:"servicemesh,omitempty" yaml:"servicemesh,omitempty" mapstructure:"servicemesh"`
|
||||
NetworkOptions *network.Options `json:"network,omitempty" yaml:"network,omitempty" mapstructure:"network"`
|
||||
LdapOptions *ldap.Options `json:"-,omitempty" yaml:"ldap,omitempty" mapstructure:"ldap"`
|
||||
RedisOptions *cache.Options `json:"redis,omitempty" yaml:"redis,omitempty" mapstructure:"redis"`
|
||||
S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"`
|
||||
OpenPitrixOptions *openpitrix.Options `json:"openpitrix,omitempty" yaml:"openpitrix,omitempty" mapstructure:"openpitrix"`
|
||||
MonitoringOptions *prometheus.Options `json:"monitoring,omitempty" yaml:"monitoring,omitempty" mapstructure:"monitoring"`
|
||||
LoggingOptions *elasticsearch.Options `json:"logging,omitempty" yaml:"logging,omitempty" mapstructure:"logging"`
|
||||
AuthenticationOptions *authoptions.AuthenticationOptions `json:"authentication,omitempty" yaml:"authentication,omitempty" mapstructure:"authentication"`
|
||||
AuthorizationOptions *authorizationoptions.AuthorizationOptions `json:"authorization,omitempty" yaml:"authorization,omitempty" mapstructure:"authorization"`
|
||||
MultiClusterOptions *multicluster.Options `json:"multicluster,omitempty" yaml:"multicluster,omitempty" mapstructure:"multicluster"`
|
||||
MultiClusterOptions *multicluster.Options `json:"multicluster,omitempty" yaml:"multicluster,omitempty" mapstructure:"multicluster"`
|
||||
// Options used for enabling components, not actually used now. Once we switch Alerting/Notification API to kubesphere,
|
||||
// we can add these options to kubesphere command lines
|
||||
AlertingOptions *alerting.Options `json:"alerting,omitempty" yaml:"alerting,omitempty" mapstructure:"alerting"`
|
||||
@@ -96,6 +98,7 @@ func New() *Config {
|
||||
LoggingOptions: elasticsearch.NewElasticSearchOptions(),
|
||||
AuthenticationOptions: authoptions.NewAuthenticateOptions(),
|
||||
AuthorizationOptions: authorizationoptions.NewAuthorizationOptions(),
|
||||
MultiClusterOptions: multicluster.NewOptions(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ func TestParseQueryParameter(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
"test normal case",
|
||||
"label=app.kubernetes.io/name:book&name=foo&status=Running&page=1&limit=10&ascending=true",
|
||||
"label=app.kubernetes.io/name=book&name=foo&status=Running&page=1&limit=10&ascending=true",
|
||||
&Query{
|
||||
Pagination: newPagination(10, 0),
|
||||
SortBy: FieldCreationTimeStamp,
|
||||
Ascending: true,
|
||||
Filters: map[Field]Value{
|
||||
FieldLabel: Value("app.kubernetes.io/name:book"),
|
||||
FieldLabel: Value("app.kubernetes.io/name=book"),
|
||||
FieldName: Value("foo"),
|
||||
FieldStatus: Value("Running"),
|
||||
},
|
||||
|
||||
@@ -136,12 +136,11 @@ func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Resp
|
||||
if subject.Kind == iamv1alpha2.ResourceKindUser {
|
||||
user, err := h.im.DescribeUser(subject.Name)
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
klog.Errorf("orphan subject: %+v", subject)
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
klog.Errorf("orphan subject: %+v", subject)
|
||||
continue
|
||||
}
|
||||
api.HandleInternalError(resp, req, err)
|
||||
return
|
||||
}
|
||||
@@ -200,12 +199,11 @@ func (h *iamHandler) ListWorkspaceUsers(request *restful.Request, response *rest
|
||||
if subject.Kind == iamv1alpha2.ResourceKindUser {
|
||||
user, err := h.im.DescribeUser(subject.Name)
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
klog.Errorf("orphan subject: %+v", subject)
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
klog.Errorf("orphan subject: %+v", subject)
|
||||
continue
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ func AddToContainer(container *restful.Container, im im.IdentityManagementInterf
|
||||
ws.Route(ws.GET("/users").
|
||||
To(handler.ListUsers).
|
||||
Doc("List all users.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
// global resource
|
||||
|
||||
@@ -9,14 +9,13 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/request"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
)
|
||||
|
||||
type tenantHandler struct {
|
||||
tenant tenant.Interface
|
||||
}
|
||||
|
||||
func newTenantHandler(_ k8s.Client, factory informers.InformerFactory) *tenantHandler {
|
||||
func newTenantHandler(factory informers.InformerFactory) *tenantHandler {
|
||||
|
||||
return &tenantHandler{
|
||||
tenant: tenant.New(factory),
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -37,9 +36,9 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, factory informers.InformerFactory) error {
|
||||
func AddToContainer(c *restful.Container, factory informers.InformerFactory) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
handler := newTenantHandler(k8sClient, factory)
|
||||
handler := newTenantHandler(factory)
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
To(handler.ListWorkspaces).
|
||||
|
||||
@@ -344,14 +344,13 @@ func (am *amOperator) ListGlobalRoles(query *query.Query) (*api.ListResult, erro
|
||||
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
|
||||
func (am *amOperator) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
|
||||
switch roleRef.Kind {
|
||||
case "Role":
|
||||
case iamv1alpha2.ResourceKindRole:
|
||||
role, err := am.k8sinformer.Rbac().V1().Roles().Lister().Roles(bindingNamespace).Get(roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.Rules, nil
|
||||
|
||||
case "ClusterRole":
|
||||
case iamv1alpha2.ResourceKindClusterRole:
|
||||
clusterRole, err := am.k8sinformer.Rbac().V1().ClusterRoles().Lister().Get(roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package im
|
||||
|
||||
import (
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
@@ -81,5 +82,12 @@ func (im *ldapOperator) CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, e
|
||||
}
|
||||
|
||||
func (im *ldapOperator) ListUsers(query *query.Query) (*api.ListResult, error) {
|
||||
panic("not implement")
|
||||
result, err := im.ldapClient.List(query)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ func (d *applicationsGetter) filter(object runtime.Object, filter query.Filter)
|
||||
return v1alpha3.DefaultObjectMetaFilter(application.ObjectMeta, filter)
|
||||
}
|
||||
|
||||
func lastUpdateTime(deployment *appv1beta1.Application) time.Time {
|
||||
lut := deployment.CreationTimestamp.Time
|
||||
for _, condition := range deployment.Status.Conditions {
|
||||
func lastUpdateTime(application *appv1beta1.Application) time.Time {
|
||||
lut := application.CreationTimestamp.Time
|
||||
for _, condition := range application.Status.Conditions {
|
||||
if condition.LastUpdateTime.After(lut) {
|
||||
lut = condition.LastUpdateTime.Time
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func (t *tenantOperator) ListNamespaces(user user.Info, workspace string, queryP
|
||||
|
||||
if decision == authorizer.DecisionAllow {
|
||||
|
||||
queryParam.Filters[query.FieldLabel] = query.Value(fmt.Sprintf("%s:%s", tenantv1alpha1.WorkspaceLabel, workspace))
|
||||
queryParam.Filters[query.FieldLabel] = query.Value(fmt.Sprintf("%s=%s", tenantv1alpha1.WorkspaceLabel, workspace))
|
||||
|
||||
result, err := t.resourceGetter.List("namespaces", "", queryParam)
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
)
|
||||
|
||||
// Interface defines CRUD behaviors of manipulating users
|
||||
@@ -20,4 +22,6 @@ type Interface interface {
|
||||
|
||||
// Authenticate checks if (name, password) is valid, return ErrInvalidCredentials if not
|
||||
Authenticate(name string, password string) error
|
||||
|
||||
List(query *query.Query) (*api.ListResult, error)
|
||||
}
|
||||
|
||||
@@ -22,8 +22,13 @@ import (
|
||||
"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"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -109,6 +114,7 @@ func (l *ldapInterfaceImpl) createSearchBase() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
createIfNotExistsFunc := func(request *ldap.AddRequest) error {
|
||||
searchRequest := &ldap.SearchRequest{
|
||||
@@ -165,10 +171,10 @@ func (l *ldapInterfaceImpl) newConn() (ldap.Client, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
err = conn.Bind(l.managerDN, l.managerPassword)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
@@ -357,6 +363,7 @@ func (l *ldapInterfaceImpl) Authenticate(username, password string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
dn := l.dnForUsername(username)
|
||||
err = conn.Bind(dn, password)
|
||||
@@ -365,3 +372,106 @@ func (l *ldapInterfaceImpl) Authenticate(username, password string) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (l *ldapInterfaceImpl) List(query *query.Query) (*api.ListResult, error) {
|
||||
conn, err := l.newConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
pageControl := ldap.NewControlPaging(1000)
|
||||
|
||||
users := make([]iamv1alpha2.User, 0)
|
||||
|
||||
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"},
|
||||
[]ldap.Control{pageControl},
|
||||
)
|
||||
|
||||
response, err := conn.Search(userSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("search user", 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"))
|
||||
|
||||
user := iamv1alpha2.User{ObjectMeta: metav1.ObjectMeta{Name: uid, CreationTimestamp: metav1.Time{Time: createTimestamp}}, Spec: iamv1alpha2.UserSpec{
|
||||
Email: email,
|
||||
Lang: lang,
|
||||
Description: description,
|
||||
}}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
if !query.Ascending {
|
||||
i, j = j, i
|
||||
}
|
||||
switch query.SortBy {
|
||||
case "username":
|
||||
return strings.Compare(users[i].Name, users[j].Name) <= 0
|
||||
case "createTime":
|
||||
fallthrough
|
||||
default:
|
||||
return users[i].CreationTimestamp.Before(&users[j].CreationTimestamp)
|
||||
}
|
||||
})
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for i, user := range users {
|
||||
if i >= query.Pagination.Offset && len(items) < query.Pagination.Limit {
|
||||
items = append(items, user)
|
||||
}
|
||||
}
|
||||
|
||||
return &api.ListResult{
|
||||
Items: items,
|
||||
TotalItems: len(users),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package ldap
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
)
|
||||
|
||||
// simpleLdap is a implementation of ldap.Interface, you should never use this in production env!
|
||||
@@ -74,3 +76,16 @@ func (s simpleLdap) Authenticate(name string, password string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *simpleLdap) List(query *query.Query) (*api.ListResult, error) {
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, user := range l.store {
|
||||
items = append(items, user)
|
||||
}
|
||||
|
||||
return &api.ListResult{
|
||||
Items: items,
|
||||
TotalItems: len(items),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -4,80 +4,8 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/logging"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMainBool(t *testing.T) {
|
||||
var tests = []struct {
|
||||
description string
|
||||
searchFilter logging.SearchFilter
|
||||
expected *bodyBuilder
|
||||
}{
|
||||
{
|
||||
description: "filter 2 namespaces",
|
||||
searchFilter: logging.SearchFilter{
|
||||
NamespaceFilter: map[string]time.Time{
|
||||
"kubesphere-system": time.Unix(1582000000, 0),
|
||||
"kubesphere-logging-system": time.Unix(1582969999, 0),
|
||||
},
|
||||
},
|
||||
expected: &bodyBuilder{Body{
|
||||
Query: &Query{
|
||||
Bool: Bool{
|
||||
Filter: []Match{
|
||||
{
|
||||
Bool: &Bool{
|
||||
Should: []Match{
|
||||
{
|
||||
Bool: &Bool{
|
||||
Filter: []Match{
|
||||
{
|
||||
MatchPhrase: map[string]string{"kubernetes.namespace_name.keyword": "kubesphere-system"},
|
||||
},
|
||||
{
|
||||
Range: &Range{&Time{Gte: func() *time.Time { t := time.Unix(1582000000, 0); return &t }()}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Bool: &Bool{
|
||||
Filter: []Match{
|
||||
{
|
||||
MatchPhrase: map[string]string{"kubernetes.namespace_name.keyword": "kubesphere-logging-system"},
|
||||
},
|
||||
{
|
||||
Range: &Range{&Time{Gte: func() *time.Time { t := time.Unix(1582969999, 0); return &t }()}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MinimumShouldMatch: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
body, err := newBodyBuilder().mainBool(test.searchFilter).bytes()
|
||||
expected, _ := test.expected.bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(body, expected); diff != "" {
|
||||
t.Fatalf("%T differ (-got, +want): %s", expected, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCardinalityAggregation(t *testing.T) {
|
||||
var test = struct {
|
||||
description string
|
||||
|
||||
Reference in New Issue
Block a user