Repository: vmware/govmomi
Pull request #2747 (2022-02-09 22:06:58)

fix: rest.Client.LoginByToken invalid signature
## Description

PR #2701 (ebeaa71b) added IPv6 support for signing HTTP request,
but was treating all IPs as v6.

## Type of change

Please mark options that are relevant:

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to
  not work as expected)
- [ ] This change requires a documentation update
- [ ] Build related change

## How Has This Been Tested?

Added tests and ran against real vCenter using `govc session.login -r ...`

## Checklist:

- [x] My code follows the CONTRIBUTION [guidelines](./../CONTRIBUTING.md) of
  this project
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged


Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6af4f695..37d679b2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -109,34 +109,30 @@ $ git push --force-with-lease $USER issue-<number>
 
 ### Updating Pull Requests
 
-If your PR fails to pass CI or needs changes based on code review, it's ok to
-add more commits stating the changes made, e.g. "Address review comments". This
-is to assist the reviewer(s) to easily detect and review the recent changes.
+If your PR fails to pass CI or needs changes based on code review, you'll most
+likely want to squash these changes into existing commits.
 
-In case of small PRs, it's ok to squash and force-push (see further below)
-directly instead.
+If your pull request contains a single commit or your changes are related to the
+most recent commit, you can simply amend the commit.
 
 ```console
-# incorporate review feedback
 $ git add .
-
-# create a fixup commit which will be merged into your (original) <commit>
-$ git commit --fixup <commit>
-$ git push $USER issue-<number>
+$ git commit --amend
+$ git push --force-with-lease $USER issue-<number>
 ```
 
-Be sure to add a comment to the PR indicating your new changes are ready to
-review, as Github does not generate a notification when you git push.
-
-Once the review is complete, squash and push your final commit(s):
+If you need to squash changes into an earlier commit, you can use:
 
 ```console
-# squash all commits into one
-# --autosquash will automatically detect and merge fixup commits
+$ git add .
+$ git commit --fixup <commit>
 $ git rebase -i --autosquash vmware/master
 $ git push --force-with-lease $USER issue-<number>
 ```
 
+Be sure to add a comment to the PR indicating your new changes are ready to
+review, as Github does not generate a notification when you git push.
+
 ### Code Style
 
 The coding style suggested by the Go community is used in `govmomi`. See the
diff --git a/cns/types/types.go b/cns/types/types.go
index c5fb2812..575de000 100644
--- a/cns/types/types.go
+++ b/cns/types/types.go
@@ -394,7 +394,6 @@ type CnsBlockBackingDetails struct {
 
 	BackingDiskId      string `xml:"backingDiskId,omitempty"`
 	BackingDiskUrlPath string `xml:"backingDiskUrlPath,omitempty"`
-	BackingDiskObjectId string `xml:"backingDiskObjectId,omitempty"`
 }
 
 func init() {
diff --git a/govc/USAGE.md b/govc/USAGE.md
index e52f6b78..711495a1 100644
--- a/govc/USAGE.md
+++ b/govc/USAGE.md
@@ -270,7 +270,6 @@ but appear via `govc $cmd -h`:
  - [sso.group.ls](#ssogroupls)
  - [sso.group.rm](#ssogrouprm)
  - [sso.group.update](#ssogroupupdate)
- - [sso.idp.ls](#ssoidpls)
  - [sso.service.ls](#ssoservicels)
  - [sso.user.create](#ssousercreate)
  - [sso.user.id](#ssouserid)
@@ -3722,7 +3721,6 @@ Examples:
     -cluster "Workload-Cluster" \
     -service-cidr 10.96.0.0/23 \
     -pod-cidrs 10.244.0.0/20 \
-    -control-plane-dns 10.10.10.10 \
     -control-plane-dns-names wcp.example.com \
     -workload-network.egress-cidrs 10.0.0.128/26 \
     -workload-network.ingress-cidrs "10.0.0.64/26" \
@@ -4570,20 +4568,6 @@ Options:
   -r=                    Remove user/group from group
 ```
 
-## sso.idp.ls
-
-```
-Usage: govc sso.idp.ls [OPTIONS]
-
-List SSO identity provider sources.
-
-Examples:
-  govc sso.idp.ls
-  govc sso.idp.ls -json
-
-Options:
-```
-
 ## sso.service.ls
 
 ```
diff --git a/govc/main.go b/govc/main.go
index 28451bce..5c6768a8 100644
--- a/govc/main.go
+++ b/govc/main.go
@@ -80,7 +80,6 @@ import (
 	_ "github.com/vmware/govmomi/govc/role"
 	_ "github.com/vmware/govmomi/govc/session"
 	_ "github.com/vmware/govmomi/govc/sso/group"
-	_ "github.com/vmware/govmomi/govc/sso/idp"
 	_ "github.com/vmware/govmomi/govc/sso/service"
 	_ "github.com/vmware/govmomi/govc/sso/user"
 	_ "github.com/vmware/govmomi/govc/storage/policy"
diff --git a/govc/namespace/cluster/enable.go b/govc/namespace/cluster/enable.go
index 8e5797bf..b67b6722 100644
--- a/govc/namespace/cluster/enable.go
+++ b/govc/namespace/cluster/enable.go
@@ -154,7 +154,6 @@ Examples:
     -cluster "Workload-Cluster" \
     -service-cidr 10.96.0.0/23 \
     -pod-cidrs 10.244.0.0/20 \
-    -control-plane-dns 10.10.10.10 \
     -control-plane-dns-names wcp.example.com \
     -workload-network.egress-cidrs 10.0.0.128/26 \
     -workload-network.ingress-cidrs "10.0.0.64/26" \
@@ -244,7 +243,7 @@ func (cmd *enableCluster) Run(ctx context.Context, f *flag.FlagSet) error {
 	edgeClusterDisplayName := cmd.NcpClusterNetworkSpec.NsxEdgeCluster
 	edgeClusters, err := m.ListCompatibleEdgeClusters(ctx, clusterId, switchId)
 	if err != nil {
-		return fmt.Errorf("error in compatible edge cluster lookup: %s", err)
+		return fmt.Errorf("error in compatible switch lookup: %s", err)
 	}
 
 	matchingEdgeClusters := make([]string, 0)
diff --git a/govc/sso/idp/ls.go b/govc/sso/idp/ls.go
deleted file mode 100644
index 1d75355b..00000000
--- a/govc/sso/idp/ls.go
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-Copyright (c) 2022 VMware, Inc. All Rights Reserved.
-
-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 idp
-
-import (
-	"context"
-	"flag"
-	"fmt"
-	"io"
-	"strings"
-	"text/tabwriter"
-
-	"github.com/vmware/govmomi/govc/cli"
-	"github.com/vmware/govmomi/govc/flags"
-	"github.com/vmware/govmomi/govc/sso"
-	"github.com/vmware/govmomi/ssoadmin"
-	"github.com/vmware/govmomi/ssoadmin/types"
-)
-
-type ls struct {
-	*flags.ClientFlag
-	*flags.OutputFlag
-}
-
-func init() {
-	cli.Register("sso.idp.ls", &ls{})
-}
-
-func (cmd *ls) Register(ctx context.Context, f *flag.FlagSet) {
-	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
-	cmd.ClientFlag.Register(ctx, f)
-
-	cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
-	cmd.OutputFlag.Register(ctx, f)
-}
-
-func (cmd *ls) Description() string {
-	return `List SSO identity provider sources.
-
-Examples:
-  govc sso.idp.ls
-  govc sso.idp.ls -json`
-}
-
-func (cmd *ls) Process(ctx context.Context) error {
-	if err := cmd.ClientFlag.Process(ctx); err != nil {
-		return err
-	}
-	return cmd.OutputFlag.Process(ctx)
-}
-
-type idpInfo struct {
-	IdentitySources *types.IdentitySources
-}
-
-func (r *idpInfo) Write(w io.Writer) error {
-	tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
-
-	type entry struct {
-		name   string
-		url    string
-		kind   string
-		domain string
-		alias  string
-	}
-
-	var entries []entry
-
-	for _, domain := range r.IdentitySources.System.Domains {
-		entries = append(entries, entry{"-", "-", "System Domain", domain.Name, domain.Alias})
-	}
-
-	if r.IdentitySources.LocalOS != nil {
-		for _, domain := range r.IdentitySources.LocalOS.Domains {
-			entries = append(entries, entry{"-", "-", "Local OS", domain.Name, domain.Alias})
-		}
-	}
-
-	if ad := r.IdentitySources.NativeAD; ad != nil {
-		for _, domain := range ad.Domains {
-			entries = append(entries, entry{ad.Name, "-", "Active Directory", domain.Name, domain.Alias})
-		}
-	}
-
-	for _, ldap := range r.IdentitySources.LDAPS {
-		for _, domain := range ldap.Domains {
-			entries = append(entries, entry{ldap.Name, ldap.Details.PrimaryURL, ldap.Type, domain.Name, domain.Alias})
-		}
-	}
-
-	fmt.Fprintln(tw, "Name\tServer URL\tType\tDomain\tAlias")
-
-	for _, e := range entries {
-		fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\n", e.name, e.url, e.kind, strings.ToLower(e.domain), e.alias)
-	}
-
-	return tw.Flush()
-}
-
-func (cmd *ls) Run(ctx context.Context, f *flag.FlagSet) error {
-	return sso.WithClient(ctx, cmd.ClientFlag, func(c *ssoadmin.Client) error {
-		sources, err := c.IdentitySources(ctx)
-		if err != nil {
-			return err
-		}
-
-		return cmd.WriteResult(&idpInfo{sources})
-	})
-}
diff --git a/ssoadmin/client.go b/ssoadmin/client.go
index 88f7d08f..1a03d1e5 100644
--- a/ssoadmin/client.go
+++ b/ssoadmin/client.go
@@ -441,16 +441,3 @@ func (c *Client) RevokeWSTrustRole(ctx context.Context, id types.PrincipalId, ro
 
 	return res.Returnval, nil
 }
-
-func (c *Client) IdentitySources(ctx context.Context) (*types.IdentitySources, error) {
-	req := types.Get{
-		This: c.ServiceContent.IdentitySourceManagementService,
-	}
-
-	res, err := methods.Get(ctx, c, &req)
-	if err != nil {
-		return nil, err
-	}
-
-	return &res.Returnval, nil
-}
diff --git a/ssoadmin/methods/methods.go b/ssoadmin/methods/methods.go
index 8705adff..180a4d48 100644
--- a/ssoadmin/methods/methods.go
+++ b/ssoadmin/methods/methods.go
@@ -743,26 +743,6 @@ func FindUsersInGroup(ctx context.Context, r soap.RoundTripper, req *types.FindU
 	return resBody.Res, nil
 }
 
-type GetBody struct {
-	Req    *types.Get         `xml:"urn:sso Get,omitempty"`
-	Res    *types.GetResponse `xml:"urn:sso GetResponse,omitempty"`
-	Fault_ *soap.Fault        `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
-}
-
-func (b *GetBody) Fault() *soap.Fault { return b.Fault_ }
-
-func Get(ctx context.Context, r soap.RoundTripper, req *types.Get) (*types.GetResponse, error) {
-	var reqBody, resBody GetBody
-
-	reqBody.Req = req
-
-	if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
-		return nil, err
-	}
-
-	return resBody.Res, nil
-}
-
 type GetAllCertificatesBody struct {
 	Req    *types.GetAllCertificates         `xml:"urn:sso GetAllCertificates,omitempty"`
 	Res    *types.GetAllCertificatesResponse `xml:"urn:sso GetAllCertificatesResponse,omitempty"`
diff --git a/ssoadmin/simulator/simulator.go b/ssoadmin/simulator/simulator.go
deleted file mode 100644
index e4564840..00000000
--- a/ssoadmin/simulator/simulator.go
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
-   Copyright (c) 2022 VMware, Inc. All Rights Reserved.
-
-   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 simulator
-
-import (
-	"github.com/vmware/govmomi/simulator"
-	"github.com/vmware/govmomi/ssoadmin"
-	"github.com/vmware/govmomi/ssoadmin/methods"
-	"github.com/vmware/govmomi/ssoadmin/types"
-	"github.com/vmware/govmomi/vim25/soap"
-	vim "github.com/vmware/govmomi/vim25/types"
-)
-
-func init() {
-	simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) {
-		if r.IsVPX() {
-			s.RegisterSDK(New())
-		}
-	})
-}
-
-var content = types.AdminServiceContent{
-	SessionManager:                  vim.ManagedObjectReference{Type: "SsoSessionManager", Value: "ssoSessionManager"},
-	ConfigurationManagementService:  vim.ManagedObjectReference{Type: "SsoAdminConfigurationManagementService", Value: "configurationManagementService"},
-	SmtpManagementService:           vim.ManagedObjectReference{Type: "SsoAdminSmtpManagementService", Value: "smtpManagementService"},
-	PrincipalDiscoveryService:       vim.ManagedObjectReference{Type: "SsoAdminPrincipalDiscoveryService", Value: "principalDiscoveryService"},
-	PrincipalManagementService:      vim.ManagedObjectReference{Type: "SsoAdminPrincipalManagementService", Value: "principalManagementService"},
-	RoleManagementService:           vim.ManagedObjectReference{Type: "SsoAdminRoleManagementService", Value: "roleManagementService"},
-	PasswordPolicyService:           vim.ManagedObjectReference{Type: "SsoAdminPasswordPolicyService", Value: "passwordPolicyService"},
-	LockoutPolicyService:            vim.ManagedObjectReference{Type: "SsoAdminLockoutPolicyService", Value: "lockoutPolicyService"},
-	DomainManagementService:         vim.ManagedObjectReference{Type: "SsoAdminDomainManagementService", Value: "domainManagementService"},
-	IdentitySourceManagementService: vim.ManagedObjectReference{Type: "SsoAdminIdentitySourceManagementService", Value: "identitySourceManagementService"},
-	SystemManagementService:         vim.ManagedObjectReference{Type: "SsoAdminSystemManagementService", Value: "systemManagementService"},
-	DeploymentInformationService:    vim.ManagedObjectReference{Type: "SsoAdminDeploymentInformationService", Value: "deploymentInformationService"},
-	ReplicationService:              vim.ManagedObjectReference{Type: "SsoAdminReplicationService", Value: "replicationService"},
-}
-
-var groupcheckServiceInstance = vim.ManagedObjectReference{
-	Type: "SsoGroupcheckServiceInstance", Value: "ServiceInstance",
-}
-
-var IdentitySources = types.IdentitySources{
-	System: types.IdentitySource{
-		Name:    "vsphere.local",
-		Domains: []types.Domain{{Name: "vsphere.local", Alias: "vmwarem"}},
-	},
-	LocalOS: &types.IdentitySource{
-		Name:    "localos",
-		Domains: []types.Domain{{Name: "localos", Alias: ""}},
-	},
-	NativeAD: nil,
-	LDAPS: []types.LdapIdentitySource{
-		{
-			IdentitySource: types.IdentitySource{
-				Name:    "example.com",
-				Domains: []types.Domain{{Name: "example.com", Alias: "examplex"}},
-			},
-			Type: "ActiveDirectory",
-			Details: types.LdapIdentitySourceDetails{
-				FriendlyName: "foo",
-				UserBaseDn:   "ou=People,dc=example,dc=org",
-				GroupBaseDn:  "ou=People,dc=example,dc=org",
-				PrimaryURL:   "ldap://10.168.194.120:389",
-				FailoverURL:  "",
-			},
-			AuthenticationDetails: types.AuthenticationDetails{
-				AuthenticationType: "PASSWORD",
-				Username:           "cn=admin,dc=example,dc=org",
-			},
-		},
-	},
-}
-
-type ServiceInstance struct {
-	vim.ManagedObjectReference
-}
-
-type GroupcheckServiceInstance struct {
-	vim.ManagedObjectReference
-}
-
-type SessionManager struct {
-	vim.ManagedObjectReference
-}
-
-type IdentitySourceManagementService struct {
-	vim.ManagedObjectReference
-}
-
-func New() *simulator.Registry {
-	r := simulator.NewRegistry()
-	r.Namespace = ssoadmin.Namespace
-	r.Path = ssoadmin.Path
-
-	r.Put(&ServiceInstance{
-		ManagedObjectReference: ssoadmin.ServiceInstance,
-	})
-
-	r.Put(&GroupcheckServiceInstance{
-		ManagedObjectReference: groupcheckServiceInstance,
-	})
-
-	r.Put(&SessionManager{
-		ManagedObjectReference: content.SessionManager,
-	})
-
-	r.Put(&IdentitySourceManagementService{
-		ManagedObjectReference: content.IdentitySourceManagementService,
-	})
-
-	return r
-}
-
-func (s *ServiceInstance) SsoAdminServiceInstance(ctx *simulator.Context, _ *types.SsoAdminServiceInstance) soap.HasFault {
-	return &methods.SsoAdminServiceInstanceBody{
-		Res: &types.SsoAdminServiceInstanceResponse{
-			Returnval: content,
-		},
-	}
-}
-
-func (s *GroupcheckServiceInstance) SsoGroupcheckServiceInstance(ctx *simulator.Context, _ *types.SsoGroupcheckServiceInstance) soap.HasFault {
-	return &methods.SsoGroupcheckServiceInstanceBody{
-		Res: &types.SsoGroupcheckServiceInstanceResponse{
-			Returnval: types.GroupcheckServiceContent{},
-		},
-	}
-}
-
-func (s *SessionManager) Login(ctx *simulator.Context, req *types.Login) soap.HasFault {
-	body := new(methods.LoginBody)
-
-	// TODO: check for Assertion>Subject>NameID as simulator.SessionManager.LoginByToken does
-	body.Res = new(types.LoginResponse)
-
-	return body
-}
-
-func (s *SessionManager) Logout(ctx *simulator.Context, req *types.Logout) soap.HasFault {
-	return &methods.LogoutBody{
-		Res: new(types.LogoutResponse),
-	}
-}
-
-func (s *IdentitySourceManagementService) Get(ctx *simulator.Context, _ *types.Get) soap.HasFault {
-	sources := IdentitySources
-	sources.All = nil
-	sources.All = append(sources.All, sources.System)
-
-	if sources.LocalOS != nil {
-		sources.All = append(sources.All, *sources.LocalOS)
-	}
-
-	if sources.NativeAD != nil {
-		sources.All = append(sources.All, *sources.NativeAD)
-	}
-
-	for _, ldap := range sources.LDAPS {
-		sources.All = append(sources.All, ldap.IdentitySource)
-	}
-
-	return &methods.GetBody{
-		Res: &types.GetResponse{
-			Returnval: sources,
-		},
-	}
-}
diff --git a/ssoadmin/types/types.go b/ssoadmin/types/types.go
index 49e520bc..3608dfff 100644
--- a/ssoadmin/types/types.go
+++ b/ssoadmin/types/types.go
@@ -1038,62 +1038,6 @@ type FindUsersResponse struct {
 	Returnval []AdminUser `xml:"returnval,omitempty"`
 }
 
-type Domain struct {
-	Name  string `xml:"name"`
-	Alias string `xml:"alias,omitempty"`
-}
-
-type IdentitySource struct {
-	Name    string   `xml:"name"`
-	Domains []Domain `xml:"domains"`
-}
-
-type LdapIdentitySourceDetails struct {
-	FriendlyName string `xml:"friendlyName"`
-	UserBaseDn   string `xml:"userBaseDn,omitempty"`
-	GroupBaseDn  string `xml:"groupBaseDn,omitempty"`
-	PrimaryURL   string `xml:"primaryUrl"`
-	FailoverURL  string `xml:"failoverUrl,omitempty"`
-}
-
-type AuthenticationDetails struct {
-	AuthenticationType string `xml:"authenticationType"`
-	Username           string `xml:"username"`
-}
-
-type LdapIdentitySource struct {
-	IdentitySource
-	Type                  string                    `xml:"type"`
-	Details               LdapIdentitySourceDetails `xml:"details"`
-	AuthenticationDetails AuthenticationDetails     `xml:"authenticationDetails"`
-}
-
-type IdentitySources struct {
-	All      []IdentitySource     `xml:"all"`
-	System   IdentitySource       `xml:"system"`
-	LocalOS  *IdentitySource      `xml:"localOS"`
-	NativeAD *IdentitySource      `xml:"nativeAD"`
-	LDAPS    []LdapIdentitySource `xml:"ldaps"`
-}
-
-type Get GetRequestType
-
-func init() {
-	types.Add("sso:Get", reflect.TypeOf((*Get)(nil)).Elem())
-}
-
-type GetRequestType struct {
-	This types.ManagedObjectReference `xml:"_this"`
-}
-
-func init() {
-	types.Add("sso:GetRequestType", reflect.TypeOf((*GetRequestType)(nil)).Elem())
-}
-
-type GetResponse struct {
-	Returnval IdentitySources `xml:"returnval,omitempty"`
-}
-
 type GetAllCertificates GetAllCertificatesRequestType
 
 func init() {
diff --git a/sts/signer.go b/sts/signer.go
index c6bf49d9..6ee0ffde 100644
--- a/sts/signer.go
+++ b/sts/signer.go
@@ -351,5 +351,5 @@ func isIPv6(s string) bool {
 	if ip == nil {
 		return false
 	}
-	return len(ip) == net.IPv6len
+	return ip.To4() == nil
 }
diff --git a/vapi/namespace/namespace.go b/vapi/namespace/namespace.go
index c22bfddc..3e1c21d5 100644
--- a/vapi/namespace/namespace.go
+++ b/vapi/namespace/namespace.go
@@ -188,7 +188,7 @@ type EdgeClusterCompatibilitySummary struct {
 func (c *Manager) ListCompatibleEdgeClusters(ctx context.Context, clusterId string, switchId string) (result []EdgeClusterCompatibilitySummary, err error) {
 	listUrl := c.Resource(internal.NamespaceEdgeClusterCompatibility).
 		WithParam("cluster", clusterId).
-		WithParam("compatible", "true").
-		WithPathEncodedParam("distributed_switch", switchId)
+		WithParam("distributed_switch", switchId).
+		WithParam("compatible", "true")
 	return result, c.Do(ctx, listUrl.Request(http.MethodGet), &result)
 }
diff --git a/vapi/rest/resource.go b/vapi/rest/resource.go
index e6e62749..3004abb8 100644
--- a/vapi/rest/resource.go
+++ b/vapi/rest/resource.go
@@ -51,36 +51,12 @@ func (r *Resource) WithAction(action string) *Resource {
 // WithParam adds one parameter on the URL.RawQuery
 func (r *Resource) WithParam(name string, value string) *Resource {
 	// ParseQuery handles empty case, and we control access to query string so shouldn't encounter an error case
-	params, err := url.ParseQuery(r.u.RawQuery)
-	if err != nil {
-		panic(err)
-	}
+	params, _ := url.ParseQuery(r.u.RawQuery)
 	params[name] = append(params[name], value)
 	r.u.RawQuery = params.Encode()
 	return r
 }
 
-// WithPathEncodedParam appends a parameter on the URL.RawQuery,
-// For special cases where URL Path-style encoding is needed
-func (r *Resource) WithPathEncodedParam(name string, value string) *Resource {
-	t := &url.URL{Path: value}
-	encodedValue := t.String()
-	t = &url.URL{Path: name}
-	encodedName := t.String()
-	// ParseQuery handles empty case, and we control access to query string so shouldn't encounter an error case
-	params, err := url.ParseQuery(r.u.RawQuery)
-	if err != nil {
-		panic(err)
-	}
-	// Values.Encode() doesn't escape exactly how we want, so we need to build the query string ourselves
-	if len(params) >= 1 {
-		r.u.RawQuery = r.u.RawQuery + "&" + encodedName + "=" + encodedValue
-	} else {
-		r.u.RawQuery = r.u.RawQuery + encodedName + "=" + encodedValue
-	}
-	return r
-}
-
 // Request returns a new http.Request for the given method.
 // An optional body can be provided for POST and PATCH methods.
 func (r *Resource) Request(method string, body ...interface{}) *http.Request {
diff --git a/vcsim/main.go b/vcsim/main.go
index 7876ec61..fcc4c288 100644
--- a/vcsim/main.go
+++ b/vcsim/main.go
@@ -44,7 +44,6 @@ import (
 	_ "github.com/vmware/govmomi/eam/simulator"
 	_ "github.com/vmware/govmomi/lookup/simulator"
 	_ "github.com/vmware/govmomi/pbm/simulator"
-	_ "github.com/vmware/govmomi/ssoadmin/simulator"
 	_ "github.com/vmware/govmomi/sts/simulator"
 	_ "github.com/vmware/govmomi/vapi/cluster/simulator"
 	_ "github.com/vmware/govmomi/vapi/namespace/simulator"


Test patch:
diff --git a/cns/client_test.go b/cns/client_test.go
index 33a79747..01e58053 100644
--- a/cns/client_test.go
+++ b/cns/client_test.go
@@ -262,35 +262,6 @@ func TestClient(t *testing.T) {
 		}
 	}
 
-	// Test BackingDiskObjectId field only for vVol or vSAN volume type
-	var queryFilterBackingDiskObjectIdTest cnstypes.CnsQueryFilter
-	var volumeIDListBackingDiskObjectIdTest []cnstypes.CnsVolumeId
-	volumeIDListBackingDiskObjectIdTest = append(volumeIDListBackingDiskObjectIdTest, cnstypes.CnsVolumeId{Id: volumeId})
-	queryFilterBackingDiskObjectIdTest.VolumeIds = volumeIDListBackingDiskObjectIdTest
-	t.Logf("Calling QueryVolume using queryFilter: %+v", pretty.Sprint(queryFilterBackingDiskObjectIdTest))
-	queryResultBackingDiskObjectIdTest, err := cnsClient.QueryVolume(ctx, queryFilterBackingDiskObjectIdTest)
-	if err != nil {
-		t.Errorf("Failed to query all volumes. Error: %+v \n", err)
-		t.Fatal(err)
-	}
-	t.Logf("Successfully Queried Volumes. queryResultBackingDiskObjectIdTest: %+v", pretty.Sprint(queryResultBackingDiskObjectIdTest))
-	t.Log("Checking backingDiskObjectId retieved")
-	datastoreType, err := ds.Type(ctx)
-	if err != nil {
-		t.Errorf("Failed to get datastore type. Error: %+v \n", err)
-		t.Fatal(err)
-	}
-	for _, vol := range queryResultBackingDiskObjectIdTest.Volumes {
-		// BackingDiskObjectId is only for vsan/vvol, for other type this field is empty but test should not fail
-		backingDiskObjectId := vol.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails).BackingDiskObjectId
-		if backingDiskObjectId == "" {
-			if datastoreType == vim25types.HostFileSystemVolumeFileSystemTypeVsan || datastoreType == vim25types.HostFileSystemVolumeFileSystemTypeVVOL {
-				t.Errorf("Failed to get BackingDiskObjectId")
-				t.FailNow()
-			}
-		}
-	}
-
 	// Test QuerySnapshots API on 7.0 U3 or above
 	var snapshotQueryFilter cnstypes.CnsSnapshotQueryFilter
 	var querySnapshotsTaskResult *cnstypes.CnsSnapshotQueryResult
diff --git a/govc/test/sso.bats b/govc/test/sso.bats
index d03c34e9..ff67ddb1 100755
--- a/govc/test/sso.bats
+++ b/govc/test/sso.bats
@@ -45,18 +45,4 @@ load test_helper
   govc sso.service.ls -p com.vmware.cis -t cs.identity -P wsTrust -T com.vmware.cis.cs.identity.sso -l | grep wsTrust
   govc sso.service.ls -P vmomi | grep vcenterserver | grep -v https:
   govc sso.service.ls -P vmomi -l | grep https:
-}
-
-@test "sso.idp.ls" {
-  vcsim_env
-
-  run govc sso.idp.ls -json
-  assert_success
-
-  run govc sso.idp.ls
-  assert_success
-  [ ${#lines[@]} -eq 4 ]
-  assert_matches "System Domain"
-  assert_matches "Local OS"
-  assert_matches "ActiveDirectory"
-}
+}
\ No newline at end of file
diff --git a/sts/client_test.go b/sts/client_test.go
index 8196e50c..3b49b1ad 100644
--- a/sts/client_test.go
+++ b/sts/client_test.go
@@ -30,6 +30,7 @@ import (
 	"github.com/vmware/govmomi/session"
 	"github.com/vmware/govmomi/ssoadmin"
 	"github.com/vmware/govmomi/ssoadmin/types"
+	"github.com/vmware/govmomi/vapi/rest"
 	"github.com/vmware/govmomi/vim25"
 	"github.com/vmware/govmomi/vim25/methods"
 	"github.com/vmware/govmomi/vim25/soap"
@@ -160,6 +161,12 @@ func TestIssueHOK(t *testing.T) {
 	}
 
 	log.Printf("current time=%s", now)
+
+	rc := rest.NewClient(c)
+	err = rc.LoginByToken(rc.WithSigner(ctx, s))
+	if err != nil {
+		t.Fatal(err)
+	}
 }
 
 func TestIssueTokenByToken(t *testing.T) {
diff --git a/sts/signer_test.go b/sts/signer_test.go
index f857b612..6acacc51 100644
--- a/sts/signer_test.go
+++ b/sts/signer_test.go
@@ -140,3 +140,20 @@ func TestSigner(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestIsIPv6(t *testing.T) {
+	tests := []struct {
+		ip string
+		v6 bool
+	}{
+		{"0:0:0:0:0:0:0:1", true},
+		{"10.0.0.42", false},
+	}
+
+	for _, test := range tests {
+		v6 := isIPv6(test.ip)
+		if v6 != test.v6 {
+			t.Errorf("%s: expected %t, got %t", test.ip, test.v6, v6)
+		}
+	}
+}
diff --git a/vapi/rest/resource_test.go b/vapi/rest/resource_test.go
index 5ee40d66..31778321 100644
--- a/vapi/rest/resource_test.go
+++ b/vapi/rest/resource_test.go
@@ -51,34 +51,3 @@ func TestResource_WithParam(t *testing.T) {
 		}
 	})
 }
-
-func TestResource_WithPathEncodedParam(t *testing.T) {
-	simulator.Test(func(ctx context.Context, vc *vim25.Client) {
-		c := rest.NewClient(vc)
-
-		// path is correctly formatted when Path-Encoded param is first
-		url := c.Resource("api/some/resource").
-			WithPathEncodedParam("key1", "value 1")
-		expectedPath := "api/some/resource?key1=value%201"
-		if !strings.Contains(url.String(), expectedPath) {
-			t.Errorf("First path-encoded param incorrectly added to resource, URL %q, expected path %q", url.String(), expectedPath)
-		}
-
-		// path is correctly formatted when Path-Encoded param is last
-		url = c.Resource("api/some/resource").
-			WithParam("key1", "value 1").
-			WithPathEncodedParam("key2", "value 2")
-		expectedPath = "api/some/resource?key1=value+1&key2=value%202"
-		if !strings.Contains(url.String(), expectedPath) {
-			t.Errorf("Last path-encoded param incorrectly added to resource, URL %q, expected path %q", url.String(), expectedPath)
-		}
-
-		// if WithParam is used again, it will re-encode the Path-Encoded value
-		url = url.WithParam("key3", "value 3")
-		expectedPath = "api/some/resource?key1=value+1&key2=value+2&key3=value+3"
-		if !strings.Contains(url.String(), expectedPath) {
-			t.Errorf("Middle path-encoded param not endcoded as expected, URL %q, expected path %q", url.String(), expectedPath)
-		}
-
-	})
-}