@@ -38,6 +38,11 @@ type TokenReview struct {
|
|||||||
Status *Status `json:"status,omitempty" description:"token review status"`
|
Status *Status `json:"status,omitempty" description:"token review status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoginRequest struct {
|
||||||
|
Username string `json:"username" description:"username"`
|
||||||
|
Password string `json:"password" description:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
func (request *TokenReview) Validate() error {
|
func (request *TokenReview) Validate() error {
|
||||||
if request.Spec == nil || request.Spec.Token == "" {
|
if request.Spec == nil || request.Spec.Token == "" {
|
||||||
return fmt.Errorf("token must not be null")
|
return fmt.Errorf("token must not be null")
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im
|
package iam
|
||||||
|
|
||||||
import "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
type PasswordReset struct {
|
||||||
|
CurrentPassword string `json:"currentPassword"`
|
||||||
func NewFakeOperator() IdentityManagementInterface {
|
Password string `json:"password"`
|
||||||
return NewLDAPOperator(ldap.NewSimpleLdap())
|
|
||||||
}
|
}
|
||||||
@@ -183,12 +183,11 @@ func (s *APIServer) installKubeSphereAPIs() {
|
|||||||
s.Config.MultiClusterOptions.ProxyPublishService,
|
s.Config.MultiClusterOptions.ProxyPublishService,
|
||||||
s.Config.MultiClusterOptions.ProxyPublishAddress,
|
s.Config.MultiClusterOptions.ProxyPublishAddress,
|
||||||
s.Config.MultiClusterOptions.AgentImage))
|
s.Config.MultiClusterOptions.AgentImage))
|
||||||
urlruntime.Must(iamapi.AddToContainer(s.container,
|
imOperator := im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory, s.Config.AuthenticationOptions)
|
||||||
im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory),
|
urlruntime.Must(iamapi.AddToContainer(s.container, imOperator,
|
||||||
am.NewOperator(s.InformerFactory, s.KubernetesClient.KubeSphere(), s.KubernetesClient.Kubernetes()),
|
am.NewOperator(s.InformerFactory, s.KubernetesClient.KubeSphere(), s.KubernetesClient.Kubernetes()),
|
||||||
s.Config.AuthenticationOptions))
|
s.Config.AuthenticationOptions))
|
||||||
urlruntime.Must(oauth.AddToContainer(s.container,
|
urlruntime.Must(oauth.AddToContainer(s.container, imOperator,
|
||||||
im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory),
|
|
||||||
token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient),
|
token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient),
|
||||||
s.Config.AuthenticationOptions))
|
s.Config.AuthenticationOptions))
|
||||||
urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container))
|
urlruntime.Must(servicemeshv1alpha2.AddToContainer(s.container))
|
||||||
@@ -275,7 +274,7 @@ func (s *APIServer) buildHandlerChain(stopCh <-chan struct{}) {
|
|||||||
|
|
||||||
// authenticators are unordered
|
// authenticators are unordered
|
||||||
authn := unionauth.New(anonymous.NewAuthenticator(),
|
authn := unionauth.New(anonymous.NewAuthenticator(),
|
||||||
basictoken.New(basic.NewBasicAuthenticator(im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory))),
|
basictoken.New(basic.NewBasicAuthenticator(im.NewOperator(s.KubernetesClient.KubeSphere(), s.InformerFactory, s.Config.AuthenticationOptions))),
|
||||||
bearertoken.New(jwttoken.NewTokenAuthenticator(token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient))))
|
bearertoken.New(jwttoken.NewTokenAuthenticator(token.NewJwtTokenIssuer(token.DefaultIssuerName, s.Config.AuthenticationOptions, s.CacheClient))))
|
||||||
handler = filters.WithAuthentication(handler, authn)
|
handler = filters.WithAuthentication(handler, authn)
|
||||||
handler = filters.WithRequestInfo(handler, requestInfoResolver)
|
handler = filters.WithRequestInfo(handler, requestInfoResolver)
|
||||||
|
|||||||
@@ -28,16 +28,11 @@ type AuthenticationOptions struct {
|
|||||||
// authenticate rate limit will
|
// authenticate rate limit will
|
||||||
AuthenticateRateLimiterMaxTries int `json:"authenticateRateLimiterMaxTries" yaml:"authenticateRateLimiterMaxTries"`
|
AuthenticateRateLimiterMaxTries int `json:"authenticateRateLimiterMaxTries" yaml:"authenticateRateLimiterMaxTries"`
|
||||||
AuthenticateRateLimiterDuration time.Duration `json:"authenticationRateLimiterDuration" yaml:"authenticationRateLimiterDuration"`
|
AuthenticateRateLimiterDuration time.Duration `json:"authenticationRateLimiterDuration" yaml:"authenticationRateLimiterDuration"`
|
||||||
|
|
||||||
// maximum retries when authenticate failed
|
|
||||||
MaxAuthenticateRetries int `json:"maxAuthenticateRetries" yaml:"maxAuthenticateRetries"`
|
|
||||||
|
|
||||||
// allow multiple users login at the same time
|
// allow multiple users login at the same time
|
||||||
MultipleLogin bool `json:"multipleLogin" yaml:"multipleLogin"`
|
MultipleLogin bool `json:"multipleLogin" yaml:"multipleLogin"`
|
||||||
|
|
||||||
// secret to signed jwt token
|
// secret to signed jwt token
|
||||||
JwtSecret string `json:"-" yaml:"jwtSecret"`
|
JwtSecret string `json:"-" yaml:"jwtSecret"`
|
||||||
|
// oauth options
|
||||||
OAuthOptions *oauth.Options `json:"oauthOptions" yaml:"oauthOptions"`
|
OAuthOptions *oauth.Options `json:"oauthOptions" yaml:"oauthOptions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +40,6 @@ func NewAuthenticateOptions() *AuthenticationOptions {
|
|||||||
return &AuthenticationOptions{
|
return &AuthenticationOptions{
|
||||||
AuthenticateRateLimiterMaxTries: 5,
|
AuthenticateRateLimiterMaxTries: 5,
|
||||||
AuthenticateRateLimiterDuration: time.Minute * 30,
|
AuthenticateRateLimiterDuration: time.Minute * 30,
|
||||||
MaxAuthenticateRetries: 0,
|
|
||||||
OAuthOptions: oauth.NewOptions(),
|
OAuthOptions: oauth.NewOptions(),
|
||||||
MultipleLogin: false,
|
MultipleLogin: false,
|
||||||
JwtSecret: "",
|
JwtSecret: "",
|
||||||
@@ -64,7 +58,6 @@ func (options *AuthenticationOptions) Validate() []error {
|
|||||||
func (options *AuthenticationOptions) AddFlags(fs *pflag.FlagSet, s *AuthenticationOptions) {
|
func (options *AuthenticationOptions) AddFlags(fs *pflag.FlagSet, s *AuthenticationOptions) {
|
||||||
fs.IntVar(&options.AuthenticateRateLimiterMaxTries, "authenticate-rate-limiter-max-retries", s.AuthenticateRateLimiterMaxTries, "")
|
fs.IntVar(&options.AuthenticateRateLimiterMaxTries, "authenticate-rate-limiter-max-retries", s.AuthenticateRateLimiterMaxTries, "")
|
||||||
fs.DurationVar(&options.AuthenticateRateLimiterDuration, "authenticate-rate-limiter-duration", s.AuthenticateRateLimiterDuration, "")
|
fs.DurationVar(&options.AuthenticateRateLimiterDuration, "authenticate-rate-limiter-duration", s.AuthenticateRateLimiterDuration, "")
|
||||||
fs.IntVar(&options.MaxAuthenticateRetries, "authenticate-max-retries", s.MaxAuthenticateRetries, "")
|
|
||||||
fs.BoolVar(&options.MultipleLogin, "multiple-login", s.MultipleLogin, "Allow multiple login with the same account, disable means only one user can login at the same time.")
|
fs.BoolVar(&options.MultipleLogin, "multiple-login", s.MultipleLogin, "Allow multiple login with the same account, disable means only one user can login at the same time.")
|
||||||
fs.StringVar(&options.JwtSecret, "jwt-secret", s.JwtSecret, "Secret to sign jwt token, must not be empty.")
|
fs.StringVar(&options.JwtSecret, "jwt-secret", s.JwtSecret, "Secret to sign jwt token, must not be empty.")
|
||||||
fs.DurationVar(&options.OAuthOptions.AccessTokenMaxAge, "access-token-max-age", s.OAuthOptions.AccessTokenMaxAge, "AccessTokenMaxAgeSeconds control the lifetime of access tokens, 0 means no expiration.")
|
fs.DurationVar(&options.OAuthOptions.AccessTokenMaxAge, "access-token-max-age", s.OAuthOptions.AccessTokenMaxAge, "AccessTokenMaxAgeSeconds control the lifetime of access tokens, 0 means no expiration.")
|
||||||
|
|||||||
@@ -54,16 +54,14 @@ func (s *jwtTokenIssuer) Verify(tokenString string) (User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clm := &Claims{}
|
clm := &Claims{}
|
||||||
|
|
||||||
_, err := jwt.ParseWithClaims(tokenString, clm, s.keyFunc)
|
_, err := jwt.ParseWithClaims(tokenString, clm, s.keyFunc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 means no expiration.
|
// accessTokenMaxAge = 0 or token without expiration time means that the token will not expire
|
||||||
// validate token cache
|
// do not validate token cache
|
||||||
if s.options.OAuthOptions.AccessTokenMaxAge > 0 {
|
if s.options.OAuthOptions.AccessTokenMaxAge > 0 && clm.ExpiresAt > 0 {
|
||||||
_, err = s.cache.Get(tokenCacheKey(tokenString))
|
_, err = s.cache.Get(tokenCacheKey(tokenString))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ func newTestConfig() (*Config, error) {
|
|||||||
AuthenticationOptions: &authoptions.AuthenticationOptions{
|
AuthenticationOptions: &authoptions.AuthenticationOptions{
|
||||||
AuthenticateRateLimiterMaxTries: 5,
|
AuthenticateRateLimiterMaxTries: 5,
|
||||||
AuthenticateRateLimiterDuration: 30 * time.Minute,
|
AuthenticateRateLimiterDuration: 30 * time.Minute,
|
||||||
MaxAuthenticateRetries: 6,
|
|
||||||
JwtSecret: "xxxxxx",
|
JwtSecret: "xxxxxx",
|
||||||
MultipleLogin: false,
|
MultipleLogin: false,
|
||||||
OAuthOptions: &oauth.Options{
|
OAuthOptions: &oauth.Options{
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package filters
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@@ -54,7 +55,7 @@ func WithAuthentication(handler http.Handler, auth authenticator.Request) http.H
|
|||||||
}
|
}
|
||||||
|
|
||||||
gv := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
|
gv := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
|
||||||
responsewriters.ErrorNegotiated(apierrors.NewUnauthorized("Unauthorized"), s, gv, w, req)
|
responsewriters.ErrorNegotiated(apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized:%s", err)), s, gv, w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,8 @@ func (r *ReconcileNamespace) bindWorkspace(namespace *corev1.Namespace) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeWorkspaceOwnerReferences(ownerReferences []metav1.OwnerReference) []metav1.OwnerReference {
|
func removeWorkspaceOwnerReferences(ownerReferences []metav1.OwnerReference) []metav1.OwnerReference {
|
||||||
for i, owner := range ownerReferences {
|
for i := 0; i < len(ownerReferences); i++ {
|
||||||
|
owner := ownerReferences[i]
|
||||||
if owner.Kind == tenantv1alpha1.ResourceKindWorkspace {
|
if owner.Kind == tenantv1alpha1.ResourceKindWorkspace {
|
||||||
ownerReferences = append(ownerReferences[:i], ownerReferences[i+1:]...)
|
ownerReferences = append(ownerReferences[:i], ownerReferences[i+1:]...)
|
||||||
i--
|
i--
|
||||||
|
|||||||
@@ -5,11 +5,16 @@ import (
|
|||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
|
"kubesphere.io/kubesphere/pkg/api/iam"
|
||||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||||
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizer"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apiserver/authorization/authorizerfactory"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||||
|
apirequest "kubesphere.io/kubesphere/pkg/apiserver/request"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
||||||
servererr "kubesphere.io/kubesphere/pkg/server/errors"
|
servererr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||||
@@ -17,14 +22,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type iamHandler struct {
|
type iamHandler struct {
|
||||||
am am.AccessManagementInterface
|
am am.AccessManagementInterface
|
||||||
im im.IdentityManagementInterface
|
im im.IdentityManagementInterface
|
||||||
|
authorizer authorizer.Authorizer
|
||||||
}
|
}
|
||||||
|
|
||||||
func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) *iamHandler {
|
func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) *iamHandler {
|
||||||
return &iamHandler{
|
return &iamHandler{
|
||||||
am: am,
|
am: am,
|
||||||
im: im,
|
im: im,
|
||||||
|
authorizer: authorizerfactory.NewRBACAuthorizer(am),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,24 +44,19 @@ func (h *iamHandler) DescribeUser(request *restful.Request, response *restful.Re
|
|||||||
username := request.PathParameter("user")
|
username := request.PathParameter("user")
|
||||||
|
|
||||||
user, err := h.im.DescribeUser(username)
|
user, err := h.im.DescribeUser(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
globalRole, err := h.am.GetGlobalRoleOfUser(username)
|
globalRole, err := h.am.GetGlobalRoleOfUser(username)
|
||||||
|
|
||||||
if err != nil && !errors.IsNotFound(err) {
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalRole != nil {
|
if globalRole != nil {
|
||||||
if user.Annotations == nil {
|
user = appendGlobalRoleAnnotation(user, globalRole.Name)
|
||||||
user.Annotations = make(map[string]string, 0)
|
|
||||||
}
|
|
||||||
user.Annotations[iamv1alpha2.GlobalRoleAnnotation] = globalRole.Name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteEntity(user)
|
response.WriteEntity(user)
|
||||||
@@ -66,7 +68,6 @@ func (h *iamHandler) RetrieveMemberRoleTemplates(request *restful.Request, respo
|
|||||||
username := request.PathParameter("user")
|
username := request.PathParameter("user")
|
||||||
|
|
||||||
globalRole, err := h.am.GetGlobalRoleOfUser(username)
|
globalRole, err := h.am.GetGlobalRoleOfUser(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if role binding not exist return empty list
|
// if role binding not exist return empty list
|
||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
@@ -206,20 +207,23 @@ func (h *iamHandler) ListUsers(request *restful.Request, response *restful.Respo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if globalRole != nil {
|
if globalRole != nil {
|
||||||
if user.Annotations == nil {
|
user = appendGlobalRoleAnnotation(user, globalRole.Name)
|
||||||
user.Annotations = make(map[string]string, 0)
|
|
||||||
}
|
|
||||||
user.Annotations[iamv1alpha2.GlobalRoleAnnotation] = globalRole.Name
|
|
||||||
}
|
}
|
||||||
result.Items[i] = user
|
result.Items[i] = user
|
||||||
}
|
}
|
||||||
response.WriteEntity(result)
|
response.WriteEntity(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendGlobalRoleAnnotation(user *iamv1alpha2.User, globalRole string) *iamv1alpha2.User {
|
||||||
|
if user.Annotations == nil {
|
||||||
|
user.Annotations = make(map[string]string, 0)
|
||||||
|
}
|
||||||
|
user.Annotations[iamv1alpha2.GlobalRoleAnnotation] = globalRole
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
func (h *iamHandler) ListRoles(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) ListRoles(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -266,9 +270,7 @@ func (h *iamHandler) ListNamespaceMembers(request *restful.Request, response *re
|
|||||||
}
|
}
|
||||||
|
|
||||||
queryParam.Filters[iamv1alpha2.ScopeNamespace] = query.Value(namespace)
|
queryParam.Filters[iamv1alpha2.ScopeNamespace] = query.Value(namespace)
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -280,7 +282,6 @@ func (h *iamHandler) ListNamespaceMembers(request *restful.Request, response *re
|
|||||||
func (h *iamHandler) DescribeNamespaceMember(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) DescribeNamespaceMember(request *restful.Request, response *restful.Response) {
|
||||||
username := request.PathParameter("member")
|
username := request.PathParameter("member")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -292,7 +293,6 @@ func (h *iamHandler) DescribeNamespaceMember(request *restful.Request, response
|
|||||||
queryParam.Filters[iamv1alpha2.ScopeNamespace] = query.Value(namespace)
|
queryParam.Filters[iamv1alpha2.ScopeNamespace] = query.Value(namespace)
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -334,7 +334,6 @@ func (h *iamHandler) ListWorkspaceMembers(request *restful.Request, response *re
|
|||||||
queryParam.Filters[iamv1alpha2.ScopeWorkspace] = query.Value(workspace)
|
queryParam.Filters[iamv1alpha2.ScopeWorkspace] = query.Value(workspace)
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -352,7 +351,6 @@ func (h *iamHandler) DescribeWorkspaceMember(request *restful.Request, response
|
|||||||
queryParam.Filters[iamv1alpha2.ScopeWorkspace] = query.Value(workspace)
|
queryParam.Filters[iamv1alpha2.ScopeWorkspace] = query.Value(workspace)
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -372,9 +370,7 @@ func (h *iamHandler) UpdateWorkspaceRole(request *restful.Request, response *res
|
|||||||
workspaceRoleName := request.PathParameter("workspacerole")
|
workspaceRoleName := request.PathParameter("workspacerole")
|
||||||
|
|
||||||
var workspaceRole iamv1alpha2.WorkspaceRole
|
var workspaceRole iamv1alpha2.WorkspaceRole
|
||||||
|
|
||||||
err := request.ReadEntity(&workspaceRole)
|
err := request.ReadEntity(&workspaceRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -389,7 +385,6 @@ func (h *iamHandler) UpdateWorkspaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated, err := h.am.CreateOrUpdateWorkspaceRole(workspace, &workspaceRole)
|
updated, err := h.am.CreateOrUpdateWorkspaceRole(workspace, &workspaceRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -403,9 +398,7 @@ func (h *iamHandler) CreateWorkspaceRole(request *restful.Request, response *res
|
|||||||
workspace := request.PathParameter("workspace")
|
workspace := request.PathParameter("workspace")
|
||||||
|
|
||||||
var workspaceRole iamv1alpha2.WorkspaceRole
|
var workspaceRole iamv1alpha2.WorkspaceRole
|
||||||
|
|
||||||
err := request.ReadEntity(&workspaceRole)
|
err := request.ReadEntity(&workspaceRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -413,7 +406,6 @@ func (h *iamHandler) CreateWorkspaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
created, err := h.am.CreateOrUpdateWorkspaceRole(workspace, &workspaceRole)
|
created, err := h.am.CreateOrUpdateWorkspaceRole(workspace, &workspaceRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -428,7 +420,6 @@ func (h *iamHandler) DeleteWorkspaceRole(request *restful.Request, response *res
|
|||||||
workspaceRoleName := request.PathParameter("workspacerole")
|
workspaceRoleName := request.PathParameter("workspacerole")
|
||||||
|
|
||||||
err := h.am.DeleteWorkspaceRole(workspace, workspaceRoleName)
|
err := h.am.DeleteWorkspaceRole(workspace, workspaceRoleName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -510,22 +501,62 @@ func (h *iamHandler) UpdateUser(request *restful.Request, response *restful.Resp
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalRole != "" {
|
operator, ok := apirequest.UserFrom(request.Request.Context())
|
||||||
if err := h.am.CreateGlobalRoleBinding(user.Name, globalRole); err != nil {
|
|
||||||
|
if globalRole != "" && ok {
|
||||||
|
err = h.updateGlobalRoleBinding(operator, updated, globalRole)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
handleError(request, response, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updated = appendGlobalRoleAnnotation(updated, globalRole)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.WriteEntity(updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *iamHandler) ModifyPassword(request *restful.Request, response *restful.Response) {
|
||||||
|
username := request.PathParameter("user")
|
||||||
|
|
||||||
|
var passwordReset iam.PasswordReset
|
||||||
|
err := request.ReadEntity(&passwordReset)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
api.HandleBadRequest(response, request, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
operator, ok := apirequest.UserFrom(request.Request.Context())
|
||||||
|
// change password by self
|
||||||
|
if ok && operator.GetName() == username {
|
||||||
|
_, err := h.im.Authenticate(username, passwordReset.CurrentPassword)
|
||||||
|
if err != nil {
|
||||||
|
if err == im.AuthFailedIncorrectPassword {
|
||||||
|
err = errors.NewForbidden(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularUser), username, err)
|
||||||
|
klog.Warning(err)
|
||||||
|
handleError(request, response, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteEntity(updated)
|
err = h.im.ModifyPassword(username, passwordReset.Password)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
handleError(request, response, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteEntity(servererr.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) DeleteUser(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) DeleteUser(request *restful.Request, response *restful.Response) {
|
||||||
username := request.PathParameter("user")
|
username := request.PathParameter("user")
|
||||||
|
|
||||||
err := h.im.DeleteUser(username)
|
err := h.im.DeleteUser(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -540,7 +571,6 @@ func (h *iamHandler) CreateGlobalRole(request *restful.Request, response *restfu
|
|||||||
var globalRole iamv1alpha2.GlobalRole
|
var globalRole iamv1alpha2.GlobalRole
|
||||||
|
|
||||||
err := request.ReadEntity(&globalRole)
|
err := request.ReadEntity(&globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -548,7 +578,6 @@ func (h *iamHandler) CreateGlobalRole(request *restful.Request, response *restfu
|
|||||||
}
|
}
|
||||||
|
|
||||||
created, err := h.am.CreateOrUpdateGlobalRole(&globalRole)
|
created, err := h.am.CreateOrUpdateGlobalRole(&globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -562,7 +591,6 @@ func (h *iamHandler) DeleteGlobalRole(request *restful.Request, response *restfu
|
|||||||
globalRole := request.PathParameter("globalrole")
|
globalRole := request.PathParameter("globalrole")
|
||||||
|
|
||||||
err := h.am.DeleteGlobalRole(globalRole)
|
err := h.am.DeleteGlobalRole(globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -578,7 +606,6 @@ func (h *iamHandler) UpdateGlobalRole(request *restful.Request, response *restfu
|
|||||||
var globalRole iamv1alpha2.GlobalRole
|
var globalRole iamv1alpha2.GlobalRole
|
||||||
|
|
||||||
err := request.ReadEntity(&globalRole)
|
err := request.ReadEntity(&globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -593,7 +620,6 @@ func (h *iamHandler) UpdateGlobalRole(request *restful.Request, response *restfu
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated, err := h.am.CreateOrUpdateGlobalRole(&globalRole)
|
updated, err := h.am.CreateOrUpdateGlobalRole(&globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -611,15 +637,12 @@ func (h *iamHandler) DescribeGlobalRole(request *restful.Request, response *rest
|
|||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteEntity(globalRole)
|
response.WriteEntity(globalRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) CreateClusterRole(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) CreateClusterRole(request *restful.Request, response *restful.Response) {
|
||||||
var clusterRole rbacv1.ClusterRole
|
var clusterRole rbacv1.ClusterRole
|
||||||
|
|
||||||
err := request.ReadEntity(&clusterRole)
|
err := request.ReadEntity(&clusterRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -627,7 +650,6 @@ func (h *iamHandler) CreateClusterRole(request *restful.Request, response *restf
|
|||||||
}
|
}
|
||||||
|
|
||||||
created, err := h.am.CreateOrUpdateClusterRole(&clusterRole)
|
created, err := h.am.CreateOrUpdateClusterRole(&clusterRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -641,7 +663,6 @@ func (h *iamHandler) DeleteClusterRole(request *restful.Request, response *restf
|
|||||||
clusterrole := request.PathParameter("clusterrole")
|
clusterrole := request.PathParameter("clusterrole")
|
||||||
|
|
||||||
err := h.am.DeleteClusterRole(clusterrole)
|
err := h.am.DeleteClusterRole(clusterrole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -657,7 +678,6 @@ func (h *iamHandler) UpdateClusterRole(request *restful.Request, response *restf
|
|||||||
var clusterRole rbacv1.ClusterRole
|
var clusterRole rbacv1.ClusterRole
|
||||||
|
|
||||||
err := request.ReadEntity(&clusterRole)
|
err := request.ReadEntity(&clusterRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -672,7 +692,6 @@ func (h *iamHandler) UpdateClusterRole(request *restful.Request, response *restf
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated, err := h.am.CreateOrUpdateClusterRole(&clusterRole)
|
updated, err := h.am.CreateOrUpdateClusterRole(&clusterRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -690,7 +709,6 @@ func (h *iamHandler) DescribeClusterRole(request *restful.Request, response *res
|
|||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteEntity(clusterRole)
|
response.WriteEntity(clusterRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,14 +721,12 @@ func (h *iamHandler) DescribeWorkspaceRole(request *restful.Request, response *r
|
|||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response.WriteEntity(workspaceRole)
|
response.WriteEntity(workspaceRole)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) CreateNamespaceRole(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) CreateNamespaceRole(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -718,9 +734,7 @@ func (h *iamHandler) CreateNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
var role rbacv1.Role
|
var role rbacv1.Role
|
||||||
|
|
||||||
err = request.ReadEntity(&role)
|
err = request.ReadEntity(&role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -728,7 +742,6 @@ func (h *iamHandler) CreateNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
created, err := h.am.CreateOrUpdateNamespaceRole(namespace, &role)
|
created, err := h.am.CreateOrUpdateNamespaceRole(namespace, &role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -739,10 +752,9 @@ func (h *iamHandler) CreateNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) DeleteNamespaceRole(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) DeleteNamespaceRole(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
role := request.PathParameter("role")
|
role := request.PathParameter("role")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
|
||||||
|
|
||||||
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -750,7 +762,6 @@ func (h *iamHandler) DeleteNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = h.am.DeleteNamespaceRole(namespace, role)
|
err = h.am.DeleteNamespaceRole(namespace, role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -761,10 +772,9 @@ func (h *iamHandler) DeleteNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) UpdateNamespaceRole(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) UpdateNamespaceRole(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
roleName := request.PathParameter("role")
|
roleName := request.PathParameter("role")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
|
||||||
|
|
||||||
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -772,9 +782,7 @@ func (h *iamHandler) UpdateNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
var role rbacv1.Role
|
var role rbacv1.Role
|
||||||
|
|
||||||
err = request.ReadEntity(&role)
|
err = request.ReadEntity(&role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Errorf("%+v", err)
|
klog.Errorf("%+v", err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -789,7 +797,6 @@ func (h *iamHandler) UpdateNamespaceRole(request *restful.Request, response *res
|
|||||||
}
|
}
|
||||||
|
|
||||||
updated, err := h.am.CreateOrUpdateNamespaceRole(namespace, &role)
|
updated, err := h.am.CreateOrUpdateNamespaceRole(namespace, &role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -803,9 +810,7 @@ func (h *iamHandler) CreateWorkspaceMembers(request *restful.Request, response *
|
|||||||
workspace := request.PathParameter("workspace")
|
workspace := request.PathParameter("workspace")
|
||||||
|
|
||||||
var members []Member
|
var members []Member
|
||||||
|
|
||||||
err := request.ReadEntity(&members)
|
err := request.ReadEntity(&members)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -829,7 +834,6 @@ func (h *iamHandler) RemoveWorkspaceMember(request *restful.Request, response *r
|
|||||||
username := request.PathParameter("workspacemember")
|
username := request.PathParameter("workspacemember")
|
||||||
|
|
||||||
err := h.am.RemoveUserFromWorkspace(username, workspace)
|
err := h.am.RemoveUserFromWorkspace(username, workspace)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -844,9 +848,7 @@ func (h *iamHandler) UpdateWorkspaceMember(request *restful.Request, response *r
|
|||||||
username := request.PathParameter("workspacemember")
|
username := request.PathParameter("workspacemember")
|
||||||
|
|
||||||
var member Member
|
var member Member
|
||||||
|
|
||||||
err := request.ReadEntity(&member)
|
err := request.ReadEntity(&member)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -873,7 +875,6 @@ func (h *iamHandler) UpdateWorkspaceMember(request *restful.Request, response *r
|
|||||||
func (h *iamHandler) CreateNamespaceMembers(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) CreateNamespaceMembers(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -881,9 +882,7 @@ func (h *iamHandler) CreateNamespaceMembers(request *restful.Request, response *
|
|||||||
}
|
}
|
||||||
|
|
||||||
var members []Member
|
var members []Member
|
||||||
|
|
||||||
err = request.ReadEntity(&members)
|
err = request.ReadEntity(&members)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -904,8 +903,8 @@ func (h *iamHandler) CreateNamespaceMembers(request *restful.Request, response *
|
|||||||
|
|
||||||
func (h *iamHandler) UpdateNamespaceMember(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) UpdateNamespaceMember(request *restful.Request, response *restful.Response) {
|
||||||
username := request.PathParameter("member")
|
username := request.PathParameter("member")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
|
||||||
|
|
||||||
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -913,9 +912,7 @@ func (h *iamHandler) UpdateNamespaceMember(request *restful.Request, response *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
var member Member
|
var member Member
|
||||||
|
|
||||||
err = request.ReadEntity(&member)
|
err = request.ReadEntity(&member)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -941,8 +938,8 @@ func (h *iamHandler) UpdateNamespaceMember(request *restful.Request, response *r
|
|||||||
|
|
||||||
func (h *iamHandler) RemoveNamespaceMember(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) RemoveNamespaceMember(request *restful.Request, response *restful.Response) {
|
||||||
username := request.PathParameter("member")
|
username := request.PathParameter("member")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
|
||||||
|
|
||||||
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -950,7 +947,6 @@ func (h *iamHandler) RemoveNamespaceMember(request *restful.Request, response *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = h.am.RemoveUserFromNamespace(username, namespace)
|
err = h.am.RemoveUserFromNamespace(username, namespace)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -964,7 +960,6 @@ func (h *iamHandler) CreateClusterMembers(request *restful.Request, response *re
|
|||||||
var members []Member
|
var members []Member
|
||||||
|
|
||||||
err := request.ReadEntity(&members)
|
err := request.ReadEntity(&members)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -987,7 +982,6 @@ func (h *iamHandler) RemoveClusterMember(request *restful.Request, response *res
|
|||||||
username := request.PathParameter("clustermember")
|
username := request.PathParameter("clustermember")
|
||||||
|
|
||||||
err := h.am.RemoveUserFromCluster(username)
|
err := h.am.RemoveUserFromCluster(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -1001,9 +995,7 @@ func (h *iamHandler) UpdateClusterMember(request *restful.Request, response *res
|
|||||||
username := request.PathParameter("clustermember")
|
username := request.PathParameter("clustermember")
|
||||||
|
|
||||||
var member Member
|
var member Member
|
||||||
|
|
||||||
err := request.ReadEntity(&member)
|
err := request.ReadEntity(&member)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -1035,7 +1027,6 @@ func (h *iamHandler) DescribeClusterMember(request *restful.Request, response *r
|
|||||||
queryParam.Filters[iamv1alpha2.ScopeCluster] = "true"
|
queryParam.Filters[iamv1alpha2.ScopeCluster] = "true"
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -1052,11 +1043,9 @@ func (h *iamHandler) DescribeClusterMember(request *restful.Request, response *r
|
|||||||
|
|
||||||
func (h *iamHandler) ListClusterMembers(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) ListClusterMembers(request *restful.Request, response *restful.Response) {
|
||||||
queryParam := query.ParseQueryParameter(request)
|
queryParam := query.ParseQueryParameter(request)
|
||||||
|
|
||||||
queryParam.Filters[iamv1alpha2.ScopeCluster] = "true"
|
queryParam.Filters[iamv1alpha2.ScopeCluster] = "true"
|
||||||
|
|
||||||
result, err := h.im.ListUsers(queryParam)
|
result, err := h.im.ListUsers(queryParam)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
return
|
return
|
||||||
@@ -1066,10 +1055,8 @@ func (h *iamHandler) ListClusterMembers(request *restful.Request, response *rest
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *iamHandler) DescribeNamespaceRole(request *restful.Request, response *restful.Response) {
|
func (h *iamHandler) DescribeNamespaceRole(request *restful.Request, response *restful.Response) {
|
||||||
|
|
||||||
roleName := request.PathParameter("role")
|
roleName := request.PathParameter("role")
|
||||||
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
namespace, err := h.resolveNamespace(request.PathParameter("namespace"), request.PathParameter("devops"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -1077,7 +1064,6 @@ func (h *iamHandler) DescribeNamespaceRole(request *restful.Request, response *r
|
|||||||
}
|
}
|
||||||
|
|
||||||
role, err := h.am.GetNamespaceRole(namespace, roleName)
|
role, err := h.am.GetNamespaceRole(namespace, roleName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
@@ -1108,9 +1094,7 @@ func (h *iamHandler) PatchWorkspaceRole(request *restful.Request, response *rest
|
|||||||
}
|
}
|
||||||
|
|
||||||
workspaceRole.Name = workspaceRoleName
|
workspaceRole.Name = workspaceRoleName
|
||||||
|
|
||||||
patched, err := h.am.PatchWorkspaceRole(workspaceName, &workspaceRole)
|
patched, err := h.am.PatchWorkspaceRole(workspaceName, &workspaceRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
@@ -1131,9 +1115,7 @@ func (h *iamHandler) PatchGlobalRole(request *restful.Request, response *restful
|
|||||||
}
|
}
|
||||||
|
|
||||||
globalRole.Name = globalRoleName
|
globalRole.Name = globalRoleName
|
||||||
|
|
||||||
patched, err := h.am.PatchGlobalRole(&globalRole)
|
patched, err := h.am.PatchGlobalRole(&globalRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
@@ -1160,9 +1142,7 @@ func (h *iamHandler) PatchNamespaceRole(request *restful.Request, response *rest
|
|||||||
}
|
}
|
||||||
|
|
||||||
role.Name = roleName
|
role.Name = roleName
|
||||||
|
|
||||||
patched, err := h.am.PatchNamespaceRole(namespaceName, &role)
|
patched, err := h.am.PatchNamespaceRole(namespaceName, &role)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
@@ -1183,9 +1163,7 @@ func (h *iamHandler) PatchClusterRole(request *restful.Request, response *restfu
|
|||||||
}
|
}
|
||||||
|
|
||||||
clusterRole.Name = clusterRoleName
|
clusterRole.Name = clusterRoleName
|
||||||
|
|
||||||
patched, err := h.am.PatchClusterRole(&clusterRole)
|
patched, err := h.am.PatchClusterRole(&clusterRole)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(request, response, err)
|
handleError(request, response, err)
|
||||||
return
|
return
|
||||||
@@ -1194,6 +1172,31 @@ func (h *iamHandler) PatchClusterRole(request *restful.Request, response *restfu
|
|||||||
response.WriteEntity(patched)
|
response.WriteEntity(patched)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *iamHandler) updateGlobalRoleBinding(operator user.Info, user *iamv1alpha2.User, globalRole string) error {
|
||||||
|
userManagement := authorizer.AttributesRecord{
|
||||||
|
Resource: iamv1alpha2.ResourcesPluralUser,
|
||||||
|
Verb: "update",
|
||||||
|
ResourceScope: apirequest.GlobalScope,
|
||||||
|
ResourceRequest: true,
|
||||||
|
User: operator,
|
||||||
|
}
|
||||||
|
decision, _, err := h.authorizer.Authorize(userManagement)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if decision != authorizer.DecisionAllow {
|
||||||
|
err = errors.NewForbidden(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularUser), user.Name, fmt.Errorf("update global role binding not allowed"))
|
||||||
|
klog.Warning(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := h.am.CreateGlobalRoleBinding(user.Name, globalRole); err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func handleError(request *restful.Request, response *restful.Response, err error) {
|
func handleError(request *restful.Request, response *restful.Response, err error) {
|
||||||
if errors.IsBadRequest(err) {
|
if errors.IsBadRequest(err) {
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
@@ -1201,6 +1204,8 @@ func handleError(request *restful.Request, response *restful.Response, err error
|
|||||||
api.HandleNotFound(response, request, err)
|
api.HandleNotFound(response, request, err)
|
||||||
} else if errors.IsAlreadyExists(err) {
|
} else if errors.IsAlreadyExists(err) {
|
||||||
api.HandleConflict(response, request, err)
|
api.HandleConflict(response, request, err)
|
||||||
|
} else if errors.IsForbidden(err) {
|
||||||
|
api.HandleForbidden(response, request, err)
|
||||||
} else {
|
} else {
|
||||||
api.HandleInternalError(response, request, err)
|
api.HandleInternalError(response, request, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
|
"kubesphere.io/kubesphere/pkg/api/iam"
|
||||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||||
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||||
@@ -62,6 +63,13 @@ func AddToContainer(container *restful.Container, im im.IdentityManagementInterf
|
|||||||
Param(ws.PathParameter("user", "username")).
|
Param(ws.PathParameter("user", "username")).
|
||||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.User{}).
|
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.User{}).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||||
|
ws.Route(ws.PUT("/users/{user}/password").
|
||||||
|
To(handler.ModifyPassword).
|
||||||
|
Doc("Modify user's password.").
|
||||||
|
Reads(iam.PasswordReset{}).
|
||||||
|
Param(ws.PathParameter("user", "username")).
|
||||||
|
Returns(http.StatusOK, api.StatusOK, errors.None).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||||
ws.Route(ws.GET("/users/{user}").
|
ws.Route(ws.GET("/users/{user}").
|
||||||
To(handler.DescribeUser).
|
To(handler.DescribeUser).
|
||||||
Doc("Retrieve user details.").
|
Doc("Retrieve user details.").
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ func (h *oauthHandler) AuthorizeHandler(req *restful.Request, resp *restful.Resp
|
|||||||
redirectURI := req.QueryParameter("redirect_uri")
|
redirectURI := req.QueryParameter("redirect_uri")
|
||||||
|
|
||||||
conf, err := h.options.OAuthOptions.OAuthClient(clientId)
|
conf, err := h.options.OAuthOptions.OAuthClient(clientId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
||||||
resp.WriteError(http.StatusUnauthorized, err)
|
resp.WriteError(http.StatusUnauthorized, err)
|
||||||
@@ -109,14 +108,7 @@ func (h *oauthHandler) AuthorizeHandler(req *restful.Request, resp *restful.Resp
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
expiresIn := h.options.OAuthOptions.AccessTokenMaxAge
|
token, err := h.issueTo(user.GetName())
|
||||||
|
|
||||||
if conf.AccessTokenMaxAge != nil {
|
|
||||||
expiresIn = *conf.AccessTokenMaxAge
|
|
||||||
}
|
|
||||||
|
|
||||||
accessToken, err := h.issuer.IssueTo(user, expiresIn)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
||||||
resp.WriteError(http.StatusUnauthorized, err)
|
resp.WriteError(http.StatusUnauthorized, err)
|
||||||
@@ -131,12 +123,11 @@ func (h *oauthHandler) AuthorizeHandler(req *restful.Request, resp *restful.Resp
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectURL = fmt.Sprintf("%s#access_token=%s&token_type=Bearer", redirectURL, accessToken)
|
redirectURL = fmt.Sprintf("%s#access_token=%s&token_type=Bearer", redirectURL, token.AccessToken)
|
||||||
|
|
||||||
if expiresIn > 0 {
|
if token.ExpiresIn > 0 {
|
||||||
redirectURL = fmt.Sprintf("%s&expires_in=%v", redirectURL, expiresIn.Seconds())
|
redirectURL = fmt.Sprintf("%s&expires_in=%v", redirectURL, token.ExpiresIn)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.Header().Set("Content-Type", "text/plain")
|
resp.Header().Set("Content-Type", "text/plain")
|
||||||
http.Redirect(resp, req.Request, redirectURL, http.StatusFound)
|
http.Redirect(resp, req.Request, redirectURL, http.StatusFound)
|
||||||
}
|
}
|
||||||
@@ -212,23 +203,57 @@ func (h *oauthHandler) OAuthCallBackHandler(req *restful.Request, resp *restful.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
expiresIn := h.options.OAuthOptions.AccessTokenMaxAge
|
result, err := h.issueTo(user.GetName())
|
||||||
|
|
||||||
accessToken, err := h.issuer.IssueTo(&authuser.DefaultInfo{
|
|
||||||
Name: user.GetName(),
|
|
||||||
}, expiresIn)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
||||||
resp.WriteError(http.StatusUnauthorized, err)
|
resp.WriteError(http.StatusUnauthorized, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
resp.WriteEntity(result)
|
||||||
|
}
|
||||||
|
|
||||||
result := oauth.Token{
|
func (h *oauthHandler) Login(request *restful.Request, response *restful.Response) {
|
||||||
|
var loginRequest auth.LoginRequest
|
||||||
|
|
||||||
|
err := request.ReadEntity(&loginRequest)
|
||||||
|
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusUnauthorized, fmt.Errorf("empty username or password"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.im.Authenticate(loginRequest.Username, loginRequest.Password)
|
||||||
|
if err != nil {
|
||||||
|
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
||||||
|
response.WriteError(http.StatusUnauthorized, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := h.issueTo(user.Name)
|
||||||
|
if err != nil {
|
||||||
|
err := apierrors.NewUnauthorized(fmt.Sprintf("Unauthorized: %s", err))
|
||||||
|
response.WriteError(http.StatusUnauthorized, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.WriteEntity(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *oauthHandler) issueTo(username string) (*oauth.Token, error) {
|
||||||
|
expiresIn := h.options.OAuthOptions.AccessTokenMaxAge
|
||||||
|
|
||||||
|
accessToken, err := h.issuer.IssueTo(&authuser.DefaultInfo{
|
||||||
|
Name: username,
|
||||||
|
}, expiresIn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &oauth.Token{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
ExpiresIn: int(expiresIn.Seconds()),
|
ExpiresIn: int(expiresIn.Seconds()),
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteEntity(result)
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,5 +90,20 @@ func AddToContainer(c *restful.Container, im im.IdentityManagementInterface, iss
|
|||||||
|
|
||||||
c.Add(ws)
|
c.Add(ws)
|
||||||
|
|
||||||
|
// legacy auth API
|
||||||
|
legacy := &restful.WebService{}
|
||||||
|
legacy.Path("/kapis/iam.kubesphere.io/v1alpha2/login").
|
||||||
|
Consumes(restful.MIME_JSON).
|
||||||
|
Produces(restful.MIME_JSON)
|
||||||
|
legacy.Route(legacy.POST("").
|
||||||
|
To(handler.Login).
|
||||||
|
Deprecate().
|
||||||
|
Doc("KubeSphere APIs support token-based authentication via the Authtoken request header. The POST Login API is used to retrieve the authentication token. After the authentication token is obtained, it must be inserted into the Authtoken header for all requests.").
|
||||||
|
Reads(auth.LoginRequest{}).
|
||||||
|
Returns(http.StatusOK, api.StatusOK, oauth.Token{}).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||||
|
|
||||||
|
c.Add(legacy)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ import (
|
|||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2"
|
||||||
|
authoptions "kubesphere.io/kubesphere/pkg/apiserver/authentication/options"
|
||||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||||
kubesphereclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
kubesphereclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
|
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IdentityManagementInterface interface {
|
type IdentityManagementInterface interface {
|
||||||
@@ -36,6 +38,7 @@ type IdentityManagementInterface interface {
|
|||||||
UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
|
UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error)
|
||||||
DescribeUser(username string) (*iamv1alpha2.User, error)
|
DescribeUser(username string) (*iamv1alpha2.User, error)
|
||||||
Authenticate(username, password string) (*iamv1alpha2.User, error)
|
Authenticate(username, password string) (*iamv1alpha2.User, error)
|
||||||
|
ModifyPassword(username string, password string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -45,34 +48,66 @@ var (
|
|||||||
UserNotExists = errors.New("user not exists")
|
UserNotExists = errors.New("user not exists")
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewOperator(ksClient kubesphereclient.Interface, factory informers.InformerFactory) IdentityManagementInterface {
|
func NewOperator(ksClient kubesphereclient.Interface, factory informers.InformerFactory, options *authoptions.AuthenticationOptions) IdentityManagementInterface {
|
||||||
|
im := &defaultIMOperator{
|
||||||
return &defaultIMOperator{
|
|
||||||
ksClient: ksClient,
|
ksClient: ksClient,
|
||||||
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
|
resourceGetter: resourcev1alpha3.NewResourceGetter(factory),
|
||||||
}
|
}
|
||||||
|
if options != nil {
|
||||||
|
im.authenticateRateLimiterDuration = options.AuthenticateRateLimiterDuration
|
||||||
|
im.authenticateRateLimiterMaxTries = options.AuthenticateRateLimiterMaxTries
|
||||||
|
}
|
||||||
|
return im
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultIMOperator struct {
|
type defaultIMOperator struct {
|
||||||
ksClient kubesphereclient.Interface
|
ksClient kubesphereclient.Interface
|
||||||
resourceGetter *resourcev1alpha3.ResourceGetter
|
resourceGetter *resourcev1alpha3.ResourceGetter
|
||||||
|
authenticateRateLimiterMaxTries int
|
||||||
|
authenticateRateLimiterDuration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (im *defaultIMOperator) UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
|
func (im *defaultIMOperator) UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
|
||||||
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", user.Name)
|
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", user.Name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
old := obj.(*iamv1alpha2.User).DeepCopy()
|
old := obj.(*iamv1alpha2.User).DeepCopy()
|
||||||
|
if user.Annotations == nil {
|
||||||
|
user.Annotations = make(map[string]string, 0)
|
||||||
|
}
|
||||||
user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation] = old.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]
|
user.Annotations[iamv1alpha2.PasswordEncryptedAnnotation] = old.Annotations[iamv1alpha2.PasswordEncryptedAnnotation]
|
||||||
user.Spec.EncryptedPassword = old.Spec.EncryptedPassword
|
user.Spec.EncryptedPassword = old.Spec.EncryptedPassword
|
||||||
user.Status = old.Status
|
user.Status = old.Status
|
||||||
|
|
||||||
return im.ksClient.IamV1alpha2().Users().Update(user)
|
updated, err := im.ksClient.IamV1alpha2().Users().Update(user)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ensurePasswordNotOutput(updated), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im *defaultIMOperator) ModifyPassword(username string, password string) error {
|
||||||
|
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := obj.(*iamv1alpha2.User).DeepCopy()
|
||||||
|
delete(user.Annotations, iamv1alpha2.PasswordEncryptedAnnotation)
|
||||||
|
user.Spec.EncryptedPassword = password
|
||||||
|
|
||||||
|
_, err = im.ksClient.IamV1alpha2().Users().Update(user)
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (im *defaultIMOperator) Authenticate(username, password string) (*iamv1alpha2.User, error) {
|
func (im *defaultIMOperator) Authenticate(username, password string) (*iamv1alpha2.User, error) {
|
||||||
@@ -80,26 +115,21 @@ func (im *defaultIMOperator) Authenticate(username, password string) (*iamv1alph
|
|||||||
var user *iamv1alpha2.User
|
var user *iamv1alpha2.User
|
||||||
|
|
||||||
if _, err := mail.ParseAddress(username); err != nil {
|
if _, err := mail.ParseAddress(username); err != nil {
|
||||||
|
|
||||||
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
|
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user = obj.(*iamv1alpha2.User)
|
user = obj.(*iamv1alpha2.User)
|
||||||
} else {
|
} else {
|
||||||
objs, err := im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", &query.Query{
|
objs, err := im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", &query.Query{
|
||||||
Pagination: query.NoPagination,
|
Pagination: query.NoPagination,
|
||||||
Filters: map[query.Field]query.Value{iamv1alpha2.FieldEmail: query.Value(username)},
|
Filters: map[query.Field]query.Value{iamv1alpha2.FieldEmail: query.Value(username)},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(objs.Items) != 1 {
|
if len(objs.Items) != 1 {
|
||||||
if len(objs.Items) == 0 {
|
if len(objs.Items) == 0 {
|
||||||
klog.Warningf("username or email: %s not exist", username)
|
klog.Warningf("username or email: %s not exist", username)
|
||||||
@@ -108,34 +138,36 @@ func (im *defaultIMOperator) Authenticate(username, password string) (*iamv1alph
|
|||||||
}
|
}
|
||||||
return nil, AuthFailedIncorrectPassword
|
return nil, AuthFailedIncorrectPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
user = objs.Items[0].(*iamv1alpha2.User)
|
user = objs.Items[0].(*iamv1alpha2.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if im.authRateLimitExceeded(user) {
|
||||||
|
im.authFailRecord(user, AuthRateLimitExceeded)
|
||||||
|
return nil, AuthRateLimitExceeded
|
||||||
|
}
|
||||||
|
|
||||||
if checkPasswordHash(password, user.Spec.EncryptedPassword) {
|
if checkPasswordHash(password, user.Spec.EncryptedPassword) {
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
im.authFailRecord(user, AuthFailedIncorrectPassword)
|
||||||
return nil, AuthFailedIncorrectPassword
|
return nil, AuthFailedIncorrectPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
func (im *defaultIMOperator) ListUsers(query *query.Query) (result *api.ListResult, err error) {
|
func (im *defaultIMOperator) ListUsers(query *query.Query) (result *api.ListResult, err error) {
|
||||||
result, err = im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", query)
|
result, err = im.resourceGetter.List(iamv1alpha2.ResourcesPluralUser, "", query)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
items := make([]interface{}, 0)
|
items := make([]interface{}, 0)
|
||||||
|
|
||||||
for _, item := range result.Items {
|
for _, item := range result.Items {
|
||||||
user := item.(*iamv1alpha2.User)
|
user := item.(*iamv1alpha2.User)
|
||||||
items = append(items, ensurePasswordNotOutput(user))
|
out := ensurePasswordNotOutput(user)
|
||||||
|
items = append(items, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Items = items
|
result.Items = items
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,14 +178,12 @@ func checkPasswordHash(password, hash string) bool {
|
|||||||
|
|
||||||
func (im *defaultIMOperator) DescribeUser(username string) (*iamv1alpha2.User, error) {
|
func (im *defaultIMOperator) DescribeUser(username string) (*iamv1alpha2.User, error) {
|
||||||
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
|
obj, err := im.resourceGetter.Get(iamv1alpha2.ResourcesPluralUser, "", username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Error(err)
|
klog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user := obj.(*iamv1alpha2.User)
|
user := obj.(*iamv1alpha2.User)
|
||||||
|
|
||||||
return ensurePasswordNotOutput(user), nil
|
return ensurePasswordNotOutput(user), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +200,29 @@ func (im *defaultIMOperator) CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.Us
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (im *defaultIMOperator) authRateLimitEnabled() bool {
|
||||||
|
if im.authenticateRateLimiterMaxTries <= 0 || im.authenticateRateLimiterDuration == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im *defaultIMOperator) authRateLimitExceeded(user *iamv1alpha2.User) bool {
|
||||||
|
if !im.authRateLimitEnabled() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// TODO record login history using CRD
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (im *defaultIMOperator) authFailRecord(user *iamv1alpha2.User, err error) {
|
||||||
|
if !im.authRateLimitEnabled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO record login history using CRD
|
||||||
|
}
|
||||||
|
|
||||||
func ensurePasswordNotOutput(user *iamv1alpha2.User) *iamv1alpha2.User {
|
func ensurePasswordNotOutput(user *iamv1alpha2.User) *iamv1alpha2.User {
|
||||||
out := user.DeepCopy()
|
out := user.DeepCopy()
|
||||||
// ensure encrypted password will not be output
|
// ensure encrypted password will not be output
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2020 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 im
|
|
||||||
|
|
||||||
import (
|
|
||||||
"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/simple/client/ldap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ldapOperator struct {
|
|
||||||
ldapClient ldap.Interface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLDAPOperator(ldapClient ldap.Interface) IdentityManagementInterface {
|
|
||||||
return &ldapOperator{
|
|
||||||
ldapClient: ldapClient,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) UpdateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
|
|
||||||
|
|
||||||
err := im.ldapClient.Update(user)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return im.ldapClient.Get(user.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) Authenticate(username, password string) (*iamv1alpha2.User, error) {
|
|
||||||
|
|
||||||
user, err := im.ldapClient.Get(username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = im.ldapClient.Authenticate(user.Name, password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) DescribeUser(username string) (*iamv1alpha2.User, error) {
|
|
||||||
return im.ldapClient.Get(username)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) DeleteUser(username string) error {
|
|
||||||
return im.ldapClient.Delete(username)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) CreateUser(user *iamv1alpha2.User) (*iamv1alpha2.User, error) {
|
|
||||||
err := im.ldapClient.Create(user)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (im *ldapOperator) ListUsers(query *query.Query) (*api.ListResult, error) {
|
|
||||||
result, err := im.ldapClient.List(query)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
klog.Error(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
@@ -43,10 +43,3 @@ type PodInfo struct {
|
|||||||
Pod string `json:"pod" description:"pod name"`
|
Pod string `json:"pod" description:"pod name"`
|
||||||
Container string `json:"container" description:"container name"`
|
Container string `json:"container" description:"container name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthGrantResponse struct {
|
|
||||||
TokenType string `json:"token_type,omitempty"`
|
|
||||||
Token string `json:"access_token" description:"access token"`
|
|
||||||
ExpiresIn float64 `json:"expires_in,omitempty"`
|
|
||||||
RefreshToken string `json:"refresh_token,omitempty"`
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user