vSphere: add token auth support for tags client

SAML auth support for the vCenter rest API endpoint came to govmomi
a bit after Zone support came to vSphere Cloud Provider.

Fixes #75511
pull/564/head
Doug MacEachern 2019-03-20 10:32:23 -07:00 committed by Ryler Hockenbury
parent d35c86fd8a
commit fdd0a45232
3 changed files with 50 additions and 18 deletions

View File

@ -86,34 +86,27 @@ func (connection *VSphereConnection) Connect(ctx context.Context) error {
return nil
}
// login calls SessionManager.LoginByToken if certificate and private key are configured,
// otherwise calls SessionManager.Login with user and password.
func (connection *VSphereConnection) login(ctx context.Context, client *vim25.Client) error {
m := session.NewManager(client)
connection.credentialsLock.Lock()
defer connection.credentialsLock.Unlock()
// Signer returns an sts.Signer for use with SAML token auth if connection is configured for such.
// Returns nil if username/password auth is configured for the connection.
func (connection *VSphereConnection) Signer(ctx context.Context, client *vim25.Client) (*sts.Signer, error) {
// TODO: Add separate fields for certificate and private-key.
// For now we can leave the config structs and validation as-is and
// decide to use LoginByToken if the username value is PEM encoded.
b, _ := pem.Decode([]byte(connection.Username))
if b == nil {
klog.V(3).Infof("SessionManager.Login with username '%s'", connection.Username)
return m.Login(ctx, neturl.UserPassword(connection.Username, connection.Password))
return nil, nil
}
klog.V(3).Infof("SessionManager.LoginByToken with certificate '%s'", connection.Username)
cert, err := tls.X509KeyPair([]byte(connection.Username), []byte(connection.Password))
if err != nil {
klog.Errorf("Failed to load X509 key pair. err: %+v", err)
return err
return nil, err
}
tokens, err := sts.NewClient(ctx, client)
if err != nil {
klog.Errorf("Failed to create STS client. err: %+v", err)
return err
return nil, err
}
req := sts.TokenRequest{
@ -123,9 +116,31 @@ func (connection *VSphereConnection) login(ctx context.Context, client *vim25.Cl
signer, err := tokens.Issue(ctx, req)
if err != nil {
klog.Errorf("Failed to issue SAML token. err: %+v", err)
return nil, err
}
return signer, nil
}
// login calls SessionManager.LoginByToken if certificate and private key are configured,
// otherwise calls SessionManager.Login with user and password.
func (connection *VSphereConnection) login(ctx context.Context, client *vim25.Client) error {
m := session.NewManager(client)
connection.credentialsLock.Lock()
defer connection.credentialsLock.Unlock()
signer, err := connection.Signer(ctx, client)
if err != nil {
return err
}
if signer == nil {
klog.V(3).Infof("SessionManager.Login with username %q", connection.Username)
return m.Login(ctx, neturl.UserPassword(connection.Username, connection.Password))
}
klog.V(3).Infof("SessionManager.LoginByToken with certificate %q", connection.Username)
header := soap.Header{Security: signer}
return m.LoginByToken(client.WithHeader(ctx, header))

View File

@ -38,7 +38,7 @@ import (
"github.com/vmware/govmomi/vapi/tags"
"github.com/vmware/govmomi/vim25/mo"
vmwaretypes "github.com/vmware/govmomi/vim25/types"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/informers"
@ -1432,10 +1432,20 @@ func (vs *VSphere) NodeManager() (nodeManager *NodeManager) {
func withTagsClient(ctx context.Context, connection *vclib.VSphereConnection, f func(c *rest.Client) error) error {
c := rest.NewClient(connection.Client)
user := url.UserPassword(connection.Username, connection.Password)
if err := c.Login(ctx, user); err != nil {
signer, err := connection.Signer(ctx, connection.Client)
if err != nil {
return err
}
if signer == nil {
user := url.UserPassword(connection.Username, connection.Password)
err = c.Login(ctx, user)
} else {
err = c.LoginByToken(c.WithSigner(ctx, signer))
}
if err != nil {
return err
}
defer func() {
if err := c.Logout(ctx); err != nil {
klog.Errorf("failed to logout: %v", err)

View File

@ -344,6 +344,10 @@ func TestZones(t *testing.T) {
cfg, cleanup := configFromSim()
defer cleanup()
// Configure for SAML token auth
cfg.Global.User = localhostCert
cfg.Global.Password = localhostKey
// Create vSphere configuration object
vs, err := newControllerNode(cfg)
if err != nil {
@ -382,8 +386,11 @@ func TestZones(t *testing.T) {
// Tag manager instance
m := tags.NewManager(rest.NewClient(vsi.conn.Client))
user := url.UserPassword(vsi.conn.Username, vsi.conn.Password)
if err = m.Login(ctx, user); err != nil {
signer, err := vsi.conn.Signer(ctx, vsi.conn.Client)
if err != nil {
t.Fatal(err)
}
if err = m.LoginByToken(m.WithSigner(ctx, signer)); err != nil {
t.Fatal(err)
}