add userinfo endpoint

Signed-off-by: hongming <hongming@kubesphere.io>
This commit is contained in:
hongming
2021-09-14 18:31:03 +08:00
parent 8c5c6a7dee
commit 97326a89b9
14 changed files with 168 additions and 122 deletions

View File

@@ -23,6 +23,9 @@ import (
"fmt"
"net/http"
"net/mail"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
@@ -68,6 +71,21 @@ func preRegistrationUser(idp string, identity identityprovider.Identity) authuse
}
}
func mappedUser(idp string, identity identityprovider.Identity) *iamv1alpha2.User {
// username convert
username := strings.ToLower(identity.GetUsername())
return &iamv1alpha2.User{
ObjectMeta: metav1.ObjectMeta{
Name: username,
Labels: map[string]string{
iamv1alpha2.IdentifyProviderLabel: idp,
iamv1alpha2.OriginUIDLabel: identity.GetUserID(),
},
},
Spec: iamv1alpha2.UserSpec{Email: identity.GetEmail()},
}
}
// findUser returns the user associated with the username or email
func (u *userGetter) findUser(username string) (*iamv1alpha2.User, error) {
if _, err := mail.ParseAddress(username); err != nil {

View File

@@ -22,6 +22,10 @@ import (
"context"
"net/http"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
"k8s.io/apimachinery/pkg/api/errors"
@@ -35,49 +39,60 @@ import (
)
type oauthAuthenticator struct {
*userGetter
options *authentication.Options
ksClient kubesphere.Interface
userGetter *userGetter
options *authentication.Options
}
func NewOAuthAuthenticator(userLister iamv1alpha2listers.UserLister,
func NewOAuthAuthenticator(ksClient kubesphere.Interface,
userLister iamv1alpha2listers.UserLister,
options *authentication.Options) OAuthAuthenticator {
authenticator := &oauthAuthenticator{
ksClient: ksClient,
userGetter: &userGetter{userLister: userLister},
options: options,
}
return authenticator
}
func (o oauthAuthenticator) Authenticate(ctx context.Context, provider string, req *http.Request) (authuser.Info, string, error) {
options, err := o.options.OAuthOptions.IdentityProviderOptions(provider)
func (o *oauthAuthenticator) Authenticate(_ context.Context, provider string, req *http.Request) (authuser.Info, string, error) {
providerOptions, err := o.options.OAuthOptions.IdentityProviderOptions(provider)
// identity provider not registered
if err != nil {
klog.Error(err)
return nil, "", err
}
identityProvider, err := identityprovider.GetOAuthProvider(options.Name)
oauthIdentityProvider, err := identityprovider.GetOAuthProvider(providerOptions.Name)
if err != nil {
klog.Error(err)
return nil, "", err
}
identity, err := identityProvider.IdentityExchangeCallback(req)
authenticated, err := oauthIdentityProvider.IdentityExchangeCallback(req)
if err != nil {
klog.Error(err)
return nil, "", err
}
mappedUser, err := o.findMappedUser(options.Name, identity.GetUserID())
if mappedUser == nil && options.MappingMethod == oauth.MappingMethodLookup {
user, err := o.userGetter.findMappedUser(providerOptions.Name, authenticated.GetUserID())
if user == nil && providerOptions.MappingMethod == oauth.MappingMethodLookup {
klog.Error(err)
return nil, "", err
}
// the user will automatically create and mapping when login successful.
if mappedUser == nil && options.MappingMethod == oauth.MappingMethodAuto {
return preRegistrationUser(options.Name, identity), options.Name, nil
}
if mappedUser != nil {
return &authuser.DefaultInfo{Name: mappedUser.GetName()}, options.Name, nil
if user == nil && providerOptions.MappingMethod == oauth.MappingMethodAuto {
if !providerOptions.DisableLoginConfirmation {
return preRegistrationUser(providerOptions.Name, authenticated), providerOptions.Name, nil
}
user, err = o.ksClient.IamV1alpha2().Users().Create(context.Background(), mappedUser(providerOptions.Name, authenticated), metav1.CreateOptions{})
if err != nil {
return nil, providerOptions.Name, err
}
}
return nil, "", errors.NewNotFound(iamv1alpha2.Resource(iamv1alpha2.ResourcesSingularUser), identity.GetUsername())
if user != nil {
return &authuser.DefaultInfo{Name: user.GetName()}, providerOptions.Name, nil
}
return nil, "", errors.NewNotFound(iamv1alpha2.Resource("user"), authenticated.GetUsername())
}

View File

@@ -88,6 +88,7 @@ func Test_oauthAuthenticator_Authenticate(t *testing.T) {
{
name: "Should successfully",
oauthAuthenticator: NewOAuthAuthenticator(
nil,
ksInformerFactory.Iam().V1alpha2().Users().Lister(),
oauthOptions,
),
@@ -105,6 +106,7 @@ func Test_oauthAuthenticator_Authenticate(t *testing.T) {
{
name: "Should successfully",
oauthAuthenticator: NewOAuthAuthenticator(
nil,
ksInformerFactory.Iam().V1alpha2().Users().Lister(),
oauthOptions,
),

View File

@@ -21,6 +21,10 @@ package auth
import (
"context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
"kubesphere.io/kubesphere/pkg/apiserver/authentication"
"golang.org/x/crypto/bcrypt"
@@ -36,20 +40,23 @@ import (
)
type passwordAuthenticator struct {
ksClient kubesphere.Interface
userGetter *userGetter
authOptions *authentication.Options
}
func NewPasswordAuthenticator(userLister iamv1alpha2listers.UserLister,
func NewPasswordAuthenticator(ksClient kubesphere.Interface,
userLister iamv1alpha2listers.UserLister,
options *authentication.Options) PasswordAuthenticator {
passwordAuthenticator := &passwordAuthenticator{
ksClient: ksClient,
userGetter: &userGetter{userLister: userLister},
authOptions: options,
}
return passwordAuthenticator
}
func (p *passwordAuthenticator) Authenticate(ctx context.Context, username, password string) (authuser.Info, string, error) {
func (p *passwordAuthenticator) Authenticate(_ context.Context, username, password string) (authuser.Info, string, error) {
// empty username or password are not allowed
if username == "" || password == "" {
return nil, "", IncorrectPasswordError
@@ -69,17 +76,27 @@ func (p *passwordAuthenticator) Authenticate(ctx context.Context, username, pass
return nil, providerOptions.Name, err
}
linkedAccount, err := p.userGetter.findMappedUser(providerOptions.Name, authenticated.GetUserID())
if err != nil {
return nil, providerOptions.Name, err
}
// using this method requires you to manually provision users.
if providerOptions.MappingMethod == oauth.MappingMethodLookup && linkedAccount == nil {
continue
}
// the user will automatically create and mapping when login successful.
if linkedAccount == nil && providerOptions.MappingMethod == oauth.MappingMethodAuto {
if !providerOptions.DisableLoginConfirmation {
return preRegistrationUser(providerOptions.Name, authenticated), providerOptions.Name, nil
}
linkedAccount, err = p.ksClient.IamV1alpha2().Users().Create(context.Background(), mappedUser(providerOptions.Name, authenticated), metav1.CreateOptions{})
if err != nil {
return nil, providerOptions.Name, err
}
}
if linkedAccount != nil {
return &authuser.DefaultInfo{Name: linkedAccount.GetName()}, providerOptions.Name, nil
}
// the user will automatically create and mapping when login successful.
if providerOptions.MappingMethod == oauth.MappingMethodAuto {
return preRegistrationUser(providerOptions.Name, authenticated), providerOptions.Name, nil
}
}
}