github.com/vmware/govmomi@v0.43.0/session/manager.go (about) 1 /* 2 Copyright (c) 2015 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package session 18 19 import ( 20 "context" 21 "net/url" 22 "os" 23 "strings" 24 25 "github.com/vmware/govmomi/property" 26 "github.com/vmware/govmomi/vim25" 27 "github.com/vmware/govmomi/vim25/methods" 28 "github.com/vmware/govmomi/vim25/mo" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 // Locale defaults to "en_US" and can be overridden via this var or the GOVMOMI_LOCALE env var. 33 // A value of "_" uses the server locale setting. 34 var Locale = os.Getenv("GOVMOMI_LOCALE") 35 36 func init() { 37 if Locale == "_" { 38 Locale = "" 39 } else if Locale == "" { 40 Locale = "en_US" 41 } 42 } 43 44 // Secret returns the contents if a file path value is given, otherwise returns value itself. 45 func Secret(value string) (string, error) { 46 if len(value) == 0 { 47 return value, nil 48 } 49 contents, err := os.ReadFile(value) 50 if err != nil { 51 if os.IsPermission(err) { 52 return "", err 53 } 54 return value, nil 55 } 56 return strings.TrimSpace(string(contents)), nil 57 } 58 59 type Manager struct { 60 client *vim25.Client 61 userSession *types.UserSession 62 } 63 64 func NewManager(client *vim25.Client) *Manager { 65 m := Manager{ 66 client: client, 67 } 68 69 return &m 70 } 71 72 func (sm Manager) Reference() types.ManagedObjectReference { 73 return *sm.client.ServiceContent.SessionManager 74 } 75 76 func (sm *Manager) SetLocale(ctx context.Context, locale string) error { 77 req := types.SetLocale{ 78 This: sm.Reference(), 79 Locale: locale, 80 } 81 82 _, err := methods.SetLocale(ctx, sm.client, &req) 83 return err 84 } 85 86 func (sm *Manager) Login(ctx context.Context, u *url.Userinfo) error { 87 req := types.Login{ 88 This: sm.Reference(), 89 Locale: Locale, 90 } 91 92 if u != nil { 93 req.UserName = u.Username() 94 if pw, ok := u.Password(); ok { 95 req.Password = pw 96 } 97 } 98 99 login, err := methods.Login(ctx, sm.client, &req) 100 if err != nil { 101 return err 102 } 103 104 sm.userSession = &login.Returnval 105 return nil 106 } 107 108 // LoginExtensionByCertificate uses the vCenter SDK tunnel to login using a client certificate. 109 // The client certificate can be set using the soap.Client.SetCertificate method. 110 // See: https://kb.vmware.com/s/article/2004305 111 func (sm *Manager) LoginExtensionByCertificate(ctx context.Context, key string) error { 112 c := sm.client 113 u := c.URL() 114 if u.Hostname() != "sdkTunnel" { 115 sc := c.Tunnel() 116 c = &vim25.Client{ 117 Client: sc, 118 RoundTripper: sc, 119 ServiceContent: c.ServiceContent, 120 } 121 // When http.Transport.Proxy is used, our thumbprint checker is bypassed, resulting in: 122 // "Post https://sdkTunnel:8089/sdk: x509: certificate is valid for $vcenter_hostname, not sdkTunnel" 123 // The only easy way around this is to disable verification for the call to LoginExtensionByCertificate(). 124 // TODO: find a way to avoid disabling InsecureSkipVerify. 125 c.DefaultTransport().TLSClientConfig.InsecureSkipVerify = true 126 } 127 128 req := types.LoginExtensionByCertificate{ 129 This: sm.Reference(), 130 ExtensionKey: key, 131 Locale: Locale, 132 } 133 134 login, err := methods.LoginExtensionByCertificate(ctx, c, &req) 135 if err != nil { 136 return err 137 } 138 139 // Copy the session cookie 140 sm.client.Jar.SetCookies(u, c.Jar.Cookies(c.URL())) 141 142 sm.userSession = &login.Returnval 143 return nil 144 } 145 146 func (sm *Manager) LoginByToken(ctx context.Context) error { 147 req := types.LoginByToken{ 148 This: sm.Reference(), 149 Locale: Locale, 150 } 151 152 login, err := methods.LoginByToken(ctx, sm.client, &req) 153 if err != nil { 154 return err 155 } 156 157 sm.userSession = &login.Returnval 158 return nil 159 } 160 161 func (sm *Manager) Logout(ctx context.Context) error { 162 req := types.Logout{ 163 This: sm.Reference(), 164 } 165 166 _, err := methods.Logout(ctx, sm.client, &req) 167 if err != nil { 168 return err 169 } 170 171 sm.userSession = nil 172 return nil 173 } 174 175 // UserSession retrieves and returns the SessionManager's CurrentSession field. 176 // Nil is returned if the session is not authenticated. 177 func (sm *Manager) UserSession(ctx context.Context) (*types.UserSession, error) { 178 var mgr mo.SessionManager 179 180 pc := property.DefaultCollector(sm.client) 181 err := pc.RetrieveOne(ctx, sm.Reference(), []string{"currentSession"}, &mgr) 182 if err != nil { 183 // It's OK if we can't retrieve properties because we're not authenticated 184 if f, ok := err.(types.HasFault); ok { 185 switch f.Fault().(type) { 186 case *types.NotAuthenticated: 187 return nil, nil 188 } 189 } 190 191 return nil, err 192 } 193 194 return mgr.CurrentSession, nil 195 } 196 197 func (sm *Manager) TerminateSession(ctx context.Context, sessionId []string) error { 198 req := types.TerminateSession{ 199 This: sm.Reference(), 200 SessionId: sessionId, 201 } 202 203 _, err := methods.TerminateSession(ctx, sm.client, &req) 204 return err 205 } 206 207 // SessionIsActive checks whether the session that was created at login is 208 // still valid. This function only works against vCenter. 209 func (sm *Manager) SessionIsActive(ctx context.Context) (bool, error) { 210 if sm.userSession == nil { 211 return false, nil 212 } 213 214 req := types.SessionIsActive{ 215 This: sm.Reference(), 216 SessionID: sm.userSession.Key, 217 UserName: sm.userSession.UserName, 218 } 219 220 active, err := methods.SessionIsActive(ctx, sm.client, &req) 221 if err != nil { 222 return false, err 223 } 224 225 return active.Returnval, err 226 } 227 228 func (sm *Manager) AcquireGenericServiceTicket(ctx context.Context, spec types.BaseSessionManagerServiceRequestSpec) (*types.SessionManagerGenericServiceTicket, error) { 229 req := types.AcquireGenericServiceTicket{ 230 This: sm.Reference(), 231 Spec: spec, 232 } 233 234 res, err := methods.AcquireGenericServiceTicket(ctx, sm.client, &req) 235 if err != nil { 236 return nil, err 237 } 238 239 return &res.Returnval, nil 240 } 241 242 func (sm *Manager) AcquireLocalTicket(ctx context.Context, userName string) (*types.SessionManagerLocalTicket, error) { 243 req := types.AcquireLocalTicket{ 244 This: sm.Reference(), 245 UserName: userName, 246 } 247 248 res, err := methods.AcquireLocalTicket(ctx, sm.client, &req) 249 if err != nil { 250 return nil, err 251 } 252 253 return &res.Returnval, nil 254 } 255 256 func (sm *Manager) AcquireCloneTicket(ctx context.Context) (string, error) { 257 req := types.AcquireCloneTicket{ 258 This: sm.Reference(), 259 } 260 261 res, err := methods.AcquireCloneTicket(ctx, sm.client, &req) 262 if err != nil { 263 return "", err 264 } 265 266 return res.Returnval, nil 267 } 268 269 func (sm *Manager) CloneSession(ctx context.Context, ticket string) error { 270 req := types.CloneSession{ 271 This: sm.Reference(), 272 CloneTicket: ticket, 273 } 274 275 res, err := methods.CloneSession(ctx, sm.client, &req) 276 if err != nil { 277 return err 278 } 279 280 sm.userSession = &res.Returnval 281 return nil 282 } 283 284 func (sm *Manager) UpdateServiceMessage(ctx context.Context, message string) error { 285 req := types.UpdateServiceMessage{ 286 This: sm.Reference(), 287 Message: message, 288 } 289 290 _, err := methods.UpdateServiceMessage(ctx, sm.client, &req) 291 292 return err 293 } 294 295 func (sm *Manager) ImpersonateUser(ctx context.Context, name string) error { 296 req := types.ImpersonateUser{ 297 This: sm.Reference(), 298 UserName: name, 299 Locale: Locale, 300 } 301 302 res, err := methods.ImpersonateUser(ctx, sm.client, &req) 303 if err != nil { 304 return err 305 } 306 307 sm.userSession = &res.Returnval 308 return nil 309 }