manager.go 7.0 KB

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