func TestProcess(t *testing.T) { passwd := "pass" url1, _ := soap.ParseURL("127.0.0.1") url2, _ := soap.ParseURL("root:@127.0.0.1") url3, _ := soap.ParseURL("line:[email protected]") url4, _ := soap.ParseURL("root:[email protected]") result, _ := url.Parse("https://*****:*****@127.0.0.1/sdk") passEmpty := "" result1, _ := url.Parse("https://root:@127.0.0.1/sdk") tests := []struct { URL *url.URL User string Password *string err error result *url.URL }{ {nil, "", nil, cli.NewExitError("--target argument must be specified", 1), nil}, {nil, "root", nil, cli.NewExitError("--target argument must be specified", 1), nil}, {nil, "root", &passwd, cli.NewExitError("--target argument must be specified", 1), nil}, {url1, "root", &passwd, nil, result}, {url4, "", nil, nil, result}, {url3, "root", &passwd, nil, result}, {url2, "", &passwd, nil, result}, {url1, "root", &passEmpty, nil, result1}, } for _, test := range tests { target := NewTarget() target.URL = test.URL target.User = test.User target.Password = test.Password if target.URL != nil { t.Logf("Before processing, url: %s", target.URL.String()) } e := target.HasCredentials() if test.err != nil { if e == nil { t.Errorf("Empty error") } if e.Error() != test.err.Error() { t.Errorf("Unexpected error message: %s", e.Error()) } } else if e != nil { t.Errorf("Unexpected error %s", e.Error()) } else { if target.URL != test.URL { t.Errorf("unexpected result url: %s", target.URL.String()) } else { t.Logf("result url: %s", target.URL.String()) } } } }
func (flag *ClientFlag) Set(s string) error { var err error flag.url, err = soap.ParseURL(s) return err }
func TestURLWithoutPassword(t *testing.T) { target := NewTarget() target.URL, _ = soap.ParseURL("root:[email protected]") if target.URLWithoutPassword().String() != "https://[email protected]/sdk" { t.Errorf("Unexpected return of without password URL string, %s", target.URLWithoutPassword().String()) } }
// Connect establishes the connection for the session but nothing more func (s *Session) Connect(ctx context.Context) (*Session, error) { soapURL, err := soap.ParseURL(s.Service) if soapURL == nil || err != nil { return nil, errors.Errorf("SDK URL (%s) could not be parsed: %s", s.Service, err) } // update the service URL with the resolved soapURL s.Service = soapURL.String() // we can't set a keep alive if we log in directly with client creation user := soapURL.User soapURL.User = nil // 1st connect without any userinfo to get the API type s.Client, err = govmomi.NewClient(ctx, soapURL, s.Insecure) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.String(), err) } if s.HasCertificate() && s.Client.IsVC() { // load the certificates cert, err2 := tls.X509KeyPair([]byte(s.ExtensionCert), []byte(s.ExtensionKey)) if err2 != nil { return nil, errors.Errorf("Unable to load X509 key pair(%s,%s): %s", s.ExtensionCert, s.ExtensionKey, err2) } // create the new client s.Client, err = govmomi.NewClientWithCertificate(ctx, soapURL, s.Insecure, cert) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.String(), err) } } if s.Keepalive != 0 { // now that we've verified everything, enable keepalive s.RoundTripper = session.KeepAlive(s.Client.RoundTripper, s.Keepalive) } // and now that the keepalive is registered we can log in to trigger it if !s.IsVC() || !s.HasCertificate() { log.Debugf("Trying to log in with username/password in lieu of cert") err = s.Client.Login(ctx, user) } else { log.Debugf("Logging into extension %s", s.ExtensionName) err = s.LoginExtensionByCertificate(ctx, s.ExtensionName, "") } if err != nil { return nil, errors.Errorf("Failed to log in to %s: %s", soapURL.String(), err) } s.Finder = find.NewFinder(s.Vim25(), true) // log high-level environement information s.logEnvironmentInfo() return s, nil }
// URL parses the GOVMOMI_TEST_URL environment variable if set. func URL() *url.URL { s := os.Getenv("GOVMOMI_TEST_URL") if s == "" { return nil } u, err := soap.ParseURL(s) if err != nil { panic(err) } return u }
// Duplicated to prevent cyclic dependency... func testURL(t *testing.T) *url.URL { s := os.Getenv("GOVMOMI_TEST_URL") if s == "" { t.SkipNow() } u, err := soap.ParseURL(s) if err != nil { panic(err) } return u }
// URL parses the GOVMOMI_TEST_URL environment variable if set. func URL() *url.URL { s := os.Getenv("VCENTER_URL") if s == "" { panic("VCENTER_URL env not set. Please set to url of your vcenter sdk endpoint") } u, err := soap.ParseURL(s) if err != nil { panic(err) } return u }
// renders the page for login and handles authorization requests func (s *server) loginPage(res http.ResponseWriter, req *http.Request) { defer trace.End(trace.Begin("")) ctx := context.Background() if req.Method == "POST" { // take the form data and use it to try to authenticate with vsphere // create a userconfig userconfig := session.Config{ Insecure: false, Thumbprint: rootConfig.Thumbprint, Keepalive: rootConfig.Keepalive, ClusterPath: rootConfig.ClusterPath, DatacenterPath: rootConfig.DatacenterPath, DatastorePath: rootConfig.DatastorePath, HostPath: rootConfig.Config.HostPath, PoolPath: rootConfig.PoolPath, } user := url.UserPassword(req.FormValue("username"), req.FormValue("password")) serviceURL, err := soap.ParseURL(rootConfig.Service) if err != nil { // this could happen for a number of reasons but most likely for a plain ol' auth failure log.Errorf("vSphere service URL was not a valid format; parsing returned error: %s", err) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } serviceURL.User = user userconfig.Service = serviceURL.String() // check login usersession, err := vSphereSessionGet(&userconfig) if err != nil || usersession == nil { // something went wrong or we could not authenticate log.Warnf("User %s from %s failed to authenticated at %s", user, req.RemoteAddr, time.Now()) http.Error(res, "Authentication failed due to incorrect credential(s)", 400) return } // successful login above; user is authenticated // log out, disregard errors usersession.Client.Logout(context.Background()) // create a token to save as an encrypted & signed cookie websession, err := s.uss.cookies.Get(req, sessionCookieKey) if websession == nil { log.Errorf("Web session object could not be created due to error %s", err) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } // save user config locally usersess := s.uss.Add(websession.ID, &userconfig) timeNow, err := usersess.created.MarshalText() if err != nil { log.Errorf("Failed to unmarshal time object %+v into text due to error: %s", usersess.created, err) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } websession.Values[sessionCreationTimeKey] = string(timeNow) websession.Values[sessionKey] = websession.ID remoteAddr := strings.SplitN(req.RemoteAddr, ":", 2) if len(remoteAddr) != 2 { // TODO: ctrl+f RemoteAddr and move this routine to helper log.Errorf("Format of IP address %s (should be IP:PORT) not recognized", req.RemoteAddr) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } websession.Values[ipAddressKey] = remoteAddr[0] if err := websession.Save(req, res); err != nil { log.Errorf("\"%s\" occurred while trying to save session to browser", err.Error()) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } // redirect to dashboard http.Redirect(res, req, "/", http.StatusTemporaryRedirect) return } // Render login page (shows up on non-POST requests): sess, err := client(&rootConfig) if err != nil { log.Errorf("Could not render login page due to vSphere connection error: %s", err.Error()) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } v := vicadmin.NewValidator(ctx, &vchConfig, sess) tmpl, err := template.ParseFiles("auth.html") err = tmpl.ExecuteTemplate(res, "auth.html", v) if err != nil { log.Errorf("Error parsing template: %s", err) http.Error(res, genericErrorMessage, http.StatusInternalServerError) return } }
// Connect establishes the connection for the session but nothing more func (s *Session) Connect(ctx context.Context) (*Session, error) { soapURL, err := soap.ParseURL(s.Service) if soapURL == nil || err != nil { return nil, errors.Errorf("SDK URL (%s) could not be parsed: %s", s.Service, err) } // LoginExtensionByCertificate proxies connections to a virtual host (sdkTunnel:8089) and // Go's http.Transport.DialTLS isn't called when using a proxy. Even if using a known CA, // "sdkTunnel" does not pass Go's tls.VerifyHostname check. // We are moving away from LoginExtensionByCertificate anyhow, so disable thumbprint checks for now. if s.HasCertificate() { s.Insecure = true } // Update the service URL with expanded defaults s.Service = soapURL.String() soapClient := soap.NewClient(soapURL, s.Insecure) var login func(context.Context) error if s.HasCertificate() { cert, err2 := tls.X509KeyPair([]byte(s.ExtensionCert), []byte(s.ExtensionKey)) if err2 != nil { return nil, errors.Errorf("Unable to load X509 key pair(%s,%s): %s", s.ExtensionCert, s.ExtensionKey, err2) } soapClient.SetCertificate(cert) log.Debugf("Logging in via extension %s certificate", s.ExtensionName) login = func(ctx context.Context) error { return s.LoginExtensionByCertificate(ctx, s.ExtensionName, "") } } else { log.Debugf("Logging in via username/password") login = func(ctx context.Context) error { return s.Client.Login(ctx, soapURL.User) } } soapClient.SetThumbprint(soapURL.Host, s.Thumbprint) // TODO: option to set http.Client.Transport.TLSClientConfig.RootCAs vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil { return nil, errors.Errorf("Failed to connect to %s: %s", soapURL.Host, err) } if s.Keepalive != 0 { vimClient.RoundTripper = session.KeepAliveHandler(soapClient, s.Keepalive, func(roundTripper soap.RoundTripper) error { _, err := methods.GetCurrentTime(context.Background(), roundTripper) if err == nil { return nil } log.Warnf("session keepalive error: %s", err) if isNotAuthenticated(err) { if err = login(ctx); err != nil { log.Errorf("session keepalive failed to re-authenticate: %s", err) } else { log.Info("session keepalive re-authenticated") } } return nil }) } // TODO: get rid of govmomi.Client usage, only provides a few helpers we don't need. s.Client = &govmomi.Client{ Client: vimClient, SessionManager: session.NewManager(vimClient), } err = login(ctx) if err != nil { return nil, errors.Errorf("Failed to log in to %s: %s", soapURL.Host, err) } s.Finder = find.NewFinder(s.Vim25(), false) // log high-level environment information s.logEnvironmentInfo() return s, nil }