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
This commit is contained in:
		| @@ -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)) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Doug MacEachern
					Doug MacEachern