Merge pull request #4238 from wansir/feat-4177

Support skip information reconfirm when using external IDP
This commit is contained in:
KubeSphere CI Bot
2021-09-17 09:18:51 +08:00
committed by GitHub
4 changed files with 55 additions and 8 deletions

View File

@@ -37,7 +37,8 @@ const (
GrantHandlerPrompt GrantHandlerType = "prompt"
// GrantHandlerDeny auto-denies client authorization grant requests
GrantHandlerDeny GrantHandlerType = "deny"
// MappingMethodAuto The default value.The user will automatically create and mapping when login successful.
// MappingMethodAuto The default value.
// The user will automatically create and mapping when login successful.
// Fails if a user with that username is already mapped to another identity.
MappingMethodAuto MappingMethod = "auto"
// MappingMethodLookup Looks up an existing identity, user identity mapping, and user, but does not automatically
@@ -141,6 +142,11 @@ type IdentityProviderOptions struct {
// - mixed: A user entity can be mapped with multiple identifyProvider.
MappingMethod MappingMethod `json:"mappingMethod" yaml:"mappingMethod"`
// DisableLoginConfirmation means that when the user login successfully,
// reconfirm the account information is not required.
// Username from IDP must math [a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*
DisableLoginConfirmation bool `json:"disableLoginConfirmation" yaml:"disableLoginConfirmation"`
// The type of identify provider
// OpenIDIdentityProvider LDAPIdentityProvider GitHubIdentityProvider
Type string `json:"type" yaml:"type"`

View File

@@ -136,7 +136,7 @@ identityProviders:
if err := yaml.Unmarshal([]byte(config), &options); err != nil {
t.Error(err)
}
expected := `{"identityProviders":[{"name":"ldap","mappingMethod":"auto","type":"LDAPIdentityProvider","provider":{"host":"xxxx.sn.mynetname.net:389","loginAttribute":"uid","mailAttribute":"mail","managerDN":"uid=root,cn=users,dc=xxxx,dc=sn,dc=mynetname,dc=net","userSearchBase":"dc=xxxx,dc=sn,dc=mynetname,dc=net"}},{"name":"github","mappingMethod":"mixed","type":"GitHubIdentityProvider","provider":{"clientID":"xxxxxx","endpoint":{"authURL":"https://github.com/login/oauth/authorize","tokenURL":"https://github.com/login/oauth/access_token"},"redirectURL":"https://ks-console/oauth/redirect","scopes":["user"]}}],"accessTokenMaxAge":3600000000000,"accessTokenInactivityTimeout":1800000000000}`
expected := `{"identityProviders":[{"name":"ldap","mappingMethod":"auto","disableLoginConfirmation":false,"type":"LDAPIdentityProvider","provider":{"host":"xxxx.sn.mynetname.net:389","loginAttribute":"uid","mailAttribute":"mail","managerDN":"uid=root,cn=users,dc=xxxx,dc=sn,dc=mynetname,dc=net","userSearchBase":"dc=xxxx,dc=sn,dc=mynetname,dc=net"}},{"name":"github","mappingMethod":"mixed","disableLoginConfirmation":false,"type":"GitHubIdentityProvider","provider":{"clientID":"xxxxxx","endpoint":{"authURL":"https://github.com/login/oauth/authorize","tokenURL":"https://github.com/login/oauth/access_token"},"redirectURL":"https://ks-console/oauth/redirect","scopes":["user"]}}],"accessTokenMaxAge":3600000000000,"accessTokenInactivityTimeout":1800000000000}`
output, _ := json.Marshal(options)
if expected != string(output) {
t.Errorf("expected: %s, but got: %s", expected, output)

View File

@@ -58,6 +58,10 @@ func (a *EmailValidator) Handle(ctx context.Context, req admission.Request) admi
}
func emailAlreadyExist(users v1alpha2.UserList, user *v1alpha2.User) bool {
// empty email is allowed
if user.Spec.Email == "" {
return false
}
for _, exist := range users.Items {
if exist.Spec.Email == user.Spec.Email && exist.Name != user.Name {
return true

View File

@@ -19,8 +19,12 @@
package auth
import (
"context"
"fmt"
"net/mail"
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"golang.org/x/crypto/bcrypt"
@@ -113,17 +117,27 @@ func (p *passwordAuthenticator) Authenticate(username, password string) (authuse
return nil, providerOptions.Name, err
}
linkedAccount, err := p.userGetter.findLinkedAccount(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
}
}
}
@@ -183,7 +197,22 @@ func preRegistrationUser(idp string, identity identityprovider.Identity) authuse
}
}
func (o oauth2Authenticator) Authenticate(provider, code string) (authuser.Info, string, error) {
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()},
}
}
func (o *oauth2Authenticator) Authenticate(provider, code string) (authuser.Info, string, error) {
providerOptions, err := o.authOptions.OAuthOptions.IdentityProviderOptions(provider)
// identity provider not registered
if err != nil {
@@ -206,10 +235,18 @@ func (o oauth2Authenticator) Authenticate(provider, code string) (authuser.Info,
klog.Error(err)
return nil, "", err
}
// the user will automatically create and mapping when login successful.
if user == nil && providerOptions.MappingMethod == oauth.MappingMethodAuto {
return preRegistrationUser(providerOptions.Name, authenticated), providerOptions.Name, nil
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
}
}
if user != nil {
return &authuser.DefaultInfo{Name: user.GetName()}, providerOptions.Name, nil
}