diff --git a/govc/USAGE.md b/govc/USAGE.md index 711495a12..463b82976 100644 --- a/govc/USAGE.md +++ b/govc/USAGE.md @@ -270,6 +270,7 @@ 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) @@ -4568,6 +4569,20 @@ 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 5c6768a8c..28451bce9 100644 --- a/govc/main.go +++ b/govc/main.go @@ -80,6 +80,7 @@ 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/sso/idp/ls.go b/govc/sso/idp/ls.go new file mode 100644 index 000000000..1d75355b2 --- /dev/null +++ b/govc/sso/idp/ls.go @@ -0,0 +1,123 @@ +/* +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 1a03d1e56..88f7d08ff 100644 --- a/ssoadmin/client.go +++ b/ssoadmin/client.go @@ -441,3 +441,16 @@ 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 180a4d48b..8705adffa 100644 --- a/ssoadmin/methods/methods.go +++ b/ssoadmin/methods/methods.go @@ -743,6 +743,26 @@ 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/types/types.go b/ssoadmin/types/types.go index 3608dfff9..49e520bce 100644 --- a/ssoadmin/types/types.go +++ b/ssoadmin/types/types.go @@ -1038,6 +1038,62 @@ 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() {