github.com/jfrog/jfrog-cli-core/v2@v2.51.0/utils/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"github.com/buger/jsonparser"
     8  	biutils "github.com/jfrog/build-info-go/utils"
     9  	"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
    10  	cliLog "github.com/jfrog/jfrog-cli-core/v2/utils/log"
    11  	accessAuth "github.com/jfrog/jfrog-client-go/access/auth"
    12  	artifactoryAuth "github.com/jfrog/jfrog-client-go/artifactory/auth"
    13  	"github.com/jfrog/jfrog-client-go/auth"
    14  	distributionAuth "github.com/jfrog/jfrog-client-go/distribution/auth"
    15  	lifecycleAuth "github.com/jfrog/jfrog-client-go/lifecycle/auth"
    16  	pipelinesAuth "github.com/jfrog/jfrog-client-go/pipelines/auth"
    17  	"github.com/jfrog/jfrog-client-go/utils"
    18  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    19  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    20  	"github.com/jfrog/jfrog-client-go/utils/log"
    21  	xrayAuth "github.com/jfrog/jfrog-client-go/xray/auth"
    22  	xscAuth "github.com/jfrog/jfrog-client-go/xsc/auth"
    23  	"os"
    24  	"path/filepath"
    25  	"strconv"
    26  	"strings"
    27  	"time"
    28  )
    29  
    30  func init() {
    31  	cliLog.SetDefaultLogger()
    32  }
    33  
    34  // This is the default server id. It is used when adding a server config without providing a server ID
    35  const DefaultServerId = "Default-Server"
    36  
    37  func IsServerConfExists() (bool, error) {
    38  	conf, err := readConf()
    39  	if err != nil {
    40  		return false, err
    41  	}
    42  	return conf.Servers != nil && len(conf.Servers) > 0, nil
    43  }
    44  
    45  // Returns the configured server or error if the server id was not found.
    46  // If defaultOrEmpty: return empty details if no configurations found, or default conf for empty serverId.
    47  // Exclude refreshable tokens when working with external tools (build tools, curl, etc.) or when sending requests not via ArtifactoryHttpClient.
    48  func GetSpecificConfig(serverId string, defaultOrEmpty bool, excludeRefreshableTokens bool) (*ServerDetails, error) {
    49  	configs, err := GetAllServersConfigs()
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	if defaultOrEmpty {
    55  		if len(configs) == 0 {
    56  			return new(ServerDetails), nil
    57  		}
    58  		if len(serverId) == 0 {
    59  			details, err := GetDefaultConfiguredConf(configs)
    60  			if excludeRefreshableTokens {
    61  				excludeRefreshableTokensFromDetails(details)
    62  			}
    63  			return details, errorutils.CheckError(err)
    64  		}
    65  	}
    66  
    67  	details, err := getServerConfByServerId(serverId, configs)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	if excludeRefreshableTokens {
    72  		excludeRefreshableTokensFromDetails(details)
    73  	}
    74  	return details, nil
    75  }
    76  
    77  // Disables the refreshable tokens mechanism if set in details.
    78  // We identify the refreshable tokens mechanism by having both conditions:
    79  // 1. Non-empty username and password
    80  // 2. Non-empty access and refresh token OR token refresh interval enabled
    81  func excludeRefreshableTokensFromDetails(details *ServerDetails) {
    82  	if details.WebLogin || details.User == "" || details.Password == "" {
    83  		return
    84  	}
    85  	if details.AccessToken != "" && details.ArtifactoryRefreshToken != "" ||
    86  		details.AccessToken != "" && details.RefreshToken != "" {
    87  		details.AccessToken = ""
    88  		details.ArtifactoryRefreshToken = ""
    89  		details.RefreshToken = ""
    90  	}
    91  	details.ArtifactoryTokenRefreshInterval = coreutils.TokenRefreshDisabled
    92  }
    93  
    94  // Returns the default server configuration or error if not found.
    95  // Caller should perform the check error if required.
    96  func GetDefaultConfiguredConf(configs []*ServerDetails) (*ServerDetails, error) {
    97  	if len(configs) == 0 {
    98  		details := new(ServerDetails)
    99  		details.IsDefault = true
   100  		return details, nil
   101  	}
   102  	for _, conf := range configs {
   103  		if conf.IsDefault {
   104  			return conf, nil
   105  		}
   106  	}
   107  	return nil, errors.New("couldn't find default server")
   108  }
   109  
   110  // Returns default artifactory conf. Returns nil if default server doesn't exists.
   111  func GetDefaultServerConf() (*ServerDetails, error) {
   112  	configurations, err := GetAllServersConfigs()
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  
   117  	if len(configurations) == 0 {
   118  		log.Debug("No servers were configured.")
   119  		return nil, err
   120  	}
   121  
   122  	return GetDefaultConfiguredConf(configurations)
   123  }
   124  
   125  // Returns the configured server or error if the server id not found
   126  func getServerConfByServerId(serverId string, configs []*ServerDetails) (*ServerDetails, error) {
   127  	for _, conf := range configs {
   128  		if conf.ServerId == serverId {
   129  			return conf, nil
   130  		}
   131  	}
   132  	return nil, errorutils.CheckErrorf("Server ID '%s' does not exist.", serverId)
   133  }
   134  
   135  func GetAndRemoveConfiguration(serverName string, configs []*ServerDetails) (*ServerDetails, []*ServerDetails) {
   136  	for i, conf := range configs {
   137  		if conf.ServerId == serverName {
   138  			configs = append(configs[:i], configs[i+1:]...)
   139  			return conf, configs
   140  		}
   141  	}
   142  	return nil, configs
   143  }
   144  
   145  func GetAllServersConfigs() ([]*ServerDetails, error) {
   146  	conf, err := readConf()
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	details := conf.Servers
   151  	if details == nil {
   152  		return make([]*ServerDetails, 0), nil
   153  	}
   154  	return details, nil
   155  }
   156  
   157  func SaveServersConf(details []*ServerDetails) error {
   158  	conf, err := readConf()
   159  	if err != nil {
   160  		return err
   161  	}
   162  	conf.Servers = details
   163  	conf.Version = strconv.Itoa(coreutils.GetCliConfigVersion())
   164  	return saveConfig(conf)
   165  }
   166  
   167  func saveConfig(config *Config) error {
   168  	cloneConfig, err := config.Clone()
   169  	if err != nil {
   170  		return err
   171  	}
   172  	err = cloneConfig.encrypt()
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	content, err := cloneConfig.getContent()
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	path, err := getConfFilePath()
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	err = os.WriteFile(path, content, 0600)
   188  	if err != nil {
   189  		return errorutils.CheckError(err)
   190  	}
   191  	return nil
   192  }
   193  
   194  func readConf() (*Config, error) {
   195  	config := new(Config)
   196  	content, err := getConfigFile()
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	if len(content) == 0 {
   201  		// No config file was found, returns a new empty config.
   202  		return config, nil
   203  	}
   204  	content, err = convertIfNeeded(content)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	err = json.Unmarshal(content, &config)
   210  	if err != nil {
   211  		return nil, errorutils.CheckError(err)
   212  	}
   213  
   214  	err = config.decrypt()
   215  	return config, err
   216  }
   217  
   218  func getConfigFile() (content []byte, err error) {
   219  	confFilePath, err := getConfFilePath()
   220  	if err != nil {
   221  		return
   222  	}
   223  	exists, err := fileutils.IsFileExists(confFilePath, false)
   224  	if err != nil {
   225  		return
   226  	}
   227  	if exists {
   228  		content, err = fileutils.ReadFile(confFilePath)
   229  		return
   230  	}
   231  	// Try to look for older config files
   232  	for i := coreutils.GetCliConfigVersion() - 1; i >= 3; i-- {
   233  		var versionedConfigPath string
   234  		versionedConfigPath, err = getLegacyConfigFilePath(i)
   235  		if err != nil {
   236  			return
   237  		}
   238  		exists, err = fileutils.IsFileExists(versionedConfigPath, false)
   239  		if err != nil {
   240  			return
   241  		}
   242  		if exists {
   243  			// If an old config file was found returns its content or an error.
   244  			content, err = fileutils.ReadFile(versionedConfigPath)
   245  			return
   246  		}
   247  	}
   248  
   249  	return
   250  }
   251  
   252  func (config *Config) Clone() (*Config, error) {
   253  	bytes, err := json.Marshal(config)
   254  	if err != nil {
   255  		return nil, errorutils.CheckError(err)
   256  	}
   257  	clone := &Config{}
   258  	if err = json.Unmarshal(bytes, clone); err != nil {
   259  		return nil, errorutils.CheckError(err)
   260  	}
   261  	return clone, nil
   262  }
   263  
   264  func (config *Config) getContent() ([]byte, error) {
   265  	b, err := json.Marshal(&config)
   266  	if err != nil {
   267  		return []byte{}, errorutils.CheckError(err)
   268  	}
   269  	var content bytes.Buffer
   270  	err = json.Indent(&content, b, "", "  ")
   271  	if err != nil {
   272  		return []byte{}, errorutils.CheckError(err)
   273  	}
   274  	return content.Bytes(), nil
   275  }
   276  
   277  // Move SSL certificates from the old location in security dir to certs dir.
   278  func convertCertsDir() error {
   279  	securityDir, err := coreutils.GetJfrogSecurityDir()
   280  	if err != nil {
   281  		return err
   282  	}
   283  	exists, err := fileutils.IsDirExists(securityDir, false)
   284  	// Security dir doesn't exist, no conversion needed.
   285  	if err != nil || !exists {
   286  		return err
   287  	}
   288  
   289  	certsDir, err := coreutils.GetJfrogCertsDir()
   290  	if err != nil {
   291  		return err
   292  	}
   293  	exists, err = fileutils.IsDirExists(certsDir, false)
   294  	// Certs dir already exists, no conversion needed.
   295  	if err != nil || exists {
   296  		return err
   297  	}
   298  
   299  	// Move certs to the new location.
   300  	files, err := os.ReadDir(securityDir)
   301  	if err != nil {
   302  		return errorutils.CheckError(err)
   303  	}
   304  
   305  	log.Debug("Migrating SSL certificates to the new location at: " + certsDir)
   306  	for _, f := range files {
   307  		// Skip directories and the security configuration file
   308  		if !f.IsDir() && f.Name() != coreutils.JfrogSecurityConfFile {
   309  			err = fileutils.CreateDirIfNotExist(certsDir)
   310  			if err != nil {
   311  				return err
   312  			}
   313  			err = os.Rename(filepath.Join(securityDir, f.Name()), filepath.Join(certsDir, f.Name()))
   314  			if err != nil {
   315  				return errorutils.CheckError(err)
   316  			}
   317  		}
   318  	}
   319  	return nil
   320  }
   321  
   322  // The configuration schema can change between versions, therefore we need to convert old versions to the new schema.
   323  func convertIfNeeded(content []byte) ([]byte, error) {
   324  	version, err := getVersion(content)
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  
   329  	// Switch contains FALLTHROUGH to convert from a certain version to the latest.
   330  	switch version {
   331  	case strconv.Itoa(coreutils.GetCliConfigVersion()):
   332  		return content, nil
   333  	case "0":
   334  		content, err = convertConfigV0toV1(content)
   335  		if err != nil {
   336  			return nil, err
   337  		}
   338  		fallthrough
   339  	case "1":
   340  		err = createHomeDirBackup()
   341  		if err != nil {
   342  			return nil, err
   343  		}
   344  		err = convertCertsDir()
   345  		if err != nil {
   346  			return nil, err
   347  		}
   348  		fallthrough
   349  	case "2":
   350  		content, err = convertConfigV2toV3(content)
   351  		if err != nil {
   352  			return nil, err
   353  		}
   354  		fallthrough
   355  	case "3", "4":
   356  		content, err = convertConfigV4toV5(content)
   357  		if err != nil {
   358  			return nil, err
   359  		}
   360  		fallthrough
   361  	case "5":
   362  		content, err = convertConfigV5toV6(content)
   363  	}
   364  	if err != nil {
   365  		return nil, err
   366  	}
   367  
   368  	// Save config after all conversions (also updates version).
   369  	result := new(Config)
   370  	err = json.Unmarshal(content, &result)
   371  	if errorutils.CheckError(err) != nil {
   372  		return nil, err
   373  	}
   374  	result.Version = strconv.Itoa(coreutils.GetCliConfigVersion())
   375  	err = saveConfig(result)
   376  	if err != nil {
   377  		return nil, err
   378  	}
   379  	content, err = json.Marshal(&result)
   380  	if err != nil {
   381  		return nil, errorutils.CheckError(err)
   382  	}
   383  	return content, err
   384  }
   385  
   386  // Creating a homedir backup prior to converting.
   387  func createHomeDirBackup() error {
   388  	homeDir, err := coreutils.GetJfrogHomeDir()
   389  	if err != nil {
   390  		return err
   391  	}
   392  	backupDir, err := coreutils.GetJfrogBackupDir()
   393  	if err != nil {
   394  		return err
   395  	}
   396  
   397  	// Copy homedir contents to back up dir, excluding redundant dirs and the backup dir itself.
   398  	backupName := ".jfrog-" + strconv.FormatInt(time.Now().Unix(), 10)
   399  	curBackupPath := filepath.Join(backupDir, backupName)
   400  	log.Debug("Creating a homedir backup at: " + curBackupPath)
   401  	exclude := []string{coreutils.JfrogBackupDirName, coreutils.JfrogDependenciesDirName, coreutils.JfrogLocksDirName, coreutils.JfrogLogsDirName}
   402  	return biutils.CopyDir(homeDir, curBackupPath, true, exclude)
   403  }
   404  
   405  // Version key doesn't exist in version 0
   406  // Version key is "Version" in version 1
   407  // Version key is "version" in version 2 and above
   408  func getVersion(content []byte) (value string, err error) {
   409  	value, err = jsonparser.GetString(bytes.ToLower(content), "version")
   410  	if err != nil && err.Error() == "Key path not found" {
   411  		return "0", nil
   412  	}
   413  	return value, errorutils.CheckError(err)
   414  }
   415  
   416  func convertConfigV0toV1(content []byte) ([]byte, error) {
   417  	result := new(ConfigV4)
   418  	configV0 := new(ConfigV0)
   419  	err := json.Unmarshal(content, &configV0)
   420  	if errorutils.CheckError(err) != nil {
   421  		return nil, err
   422  	}
   423  	result = configV0.Convert()
   424  	result.Version = "1"
   425  	content, err = json.Marshal(&result)
   426  	return content, errorutils.CheckError(err)
   427  }
   428  
   429  func convertConfigV2toV3(content []byte) ([]byte, error) {
   430  	config := new(ConfigV4)
   431  	err := json.Unmarshal(content, &config)
   432  	if errorutils.CheckError(err) != nil {
   433  		return nil, err
   434  	}
   435  	for _, rtConfig := range config.Artifactory {
   436  		rtConfig.User = strings.ToLower(rtConfig.User)
   437  	}
   438  	content, err = json.Marshal(&config)
   439  	return content, errorutils.CheckError(err)
   440  }
   441  
   442  func convertConfigV4toV5(content []byte) ([]byte, error) {
   443  	config := new(ConfigV4)
   444  	err := json.Unmarshal(content, &config)
   445  	if errorutils.CheckError(err) != nil {
   446  		return nil, err
   447  	}
   448  
   449  	result := config.Convert()
   450  	content, err = json.Marshal(&result)
   451  	return content, errorutils.CheckError(err)
   452  }
   453  
   454  func convertConfigV5toV6(content []byte) ([]byte, error) {
   455  	config := new(ConfigV5)
   456  	err := json.Unmarshal(content, &config)
   457  	if errorutils.CheckError(err) != nil {
   458  		return nil, err
   459  	}
   460  
   461  	result := config.Convert()
   462  	content, err = json.Marshal(&result)
   463  	return content, errorutils.CheckError(err)
   464  }
   465  
   466  func GetJfrogDependenciesPath() (string, error) {
   467  	dependenciesDir := os.Getenv(coreutils.DependenciesDir)
   468  	if dependenciesDir != "" {
   469  		return utils.AddTrailingSlashIfNeeded(dependenciesDir), nil
   470  	}
   471  	jfrogHome, err := coreutils.GetJfrogHomeDir()
   472  	if err != nil {
   473  		return "", err
   474  	}
   475  	return filepath.Join(jfrogHome, coreutils.JfrogDependenciesDirName), nil
   476  }
   477  
   478  func getConfFilePath() (string, error) {
   479  	confPath, err := coreutils.GetJfrogHomeDir()
   480  	if err != nil {
   481  		return "", err
   482  	}
   483  	err = os.MkdirAll(confPath, 0777)
   484  	if err != nil {
   485  		return "", err
   486  	}
   487  
   488  	versionString := ".v" + strconv.Itoa(coreutils.GetCliConfigVersion())
   489  	confPath = filepath.Join(confPath, coreutils.JfrogConfigFile+versionString)
   490  	return confPath, nil
   491  }
   492  
   493  func getLegacyConfigFilePath(version int) (string, error) {
   494  	confPath, err := coreutils.GetJfrogHomeDir()
   495  	if err != nil {
   496  		return "", err
   497  	}
   498  	confPath = filepath.Join(confPath, coreutils.JfrogConfigFile)
   499  	// Before version 4 all the config files were saved with the same name.
   500  	if version < 4 {
   501  		return confPath, nil
   502  	}
   503  	return confPath + ".v" + strconv.Itoa(version), nil
   504  
   505  }
   506  
   507  // Config represents the CLI latest config version.
   508  type Config struct {
   509  	ConfigV6
   510  }
   511  
   512  type ConfigV6 struct {
   513  	ConfigV5
   514  }
   515  
   516  type ConfigV5 struct {
   517  	Servers []*ServerDetails `json:"servers"`
   518  	Version string           `json:"version,omitempty"`
   519  	Enc     bool             `json:"enc,omitempty"`
   520  }
   521  
   522  // This struct is suitable for versions 1, 2, 3 and 4.
   523  type ConfigV4 struct {
   524  	Artifactory    []*ServerDetails       `json:"artifactory"`
   525  	MissionControl *MissionControlDetails `json:"missionControl,omitempty"`
   526  	Version        string                 `json:"version,omitempty"`
   527  	Enc            bool                   `json:"enc,omitempty"`
   528  }
   529  
   530  func (o *ConfigV5) Convert() *ConfigV6 {
   531  	config := new(ConfigV6)
   532  	config.Servers = o.Servers
   533  	for _, server := range config.Servers {
   534  		server.ArtifactoryRefreshToken = server.RefreshToken
   535  		server.RefreshToken = ""
   536  	}
   537  	return config
   538  }
   539  
   540  func (o *ConfigV4) Convert() *ConfigV5 {
   541  	config := new(ConfigV5)
   542  	config.Servers = o.Artifactory
   543  	for _, server := range config.Servers {
   544  		server.ArtifactoryUrl = server.Url
   545  		server.Url = ""
   546  		if server.IsDefault && o.MissionControl != nil {
   547  			server.MissionControlUrl = o.MissionControl.Url
   548  		}
   549  	}
   550  	return config
   551  }
   552  
   553  // This struct was created before the version property was added to the config.
   554  type ConfigV0 struct {
   555  	Artifactory    *ServerDetails         `json:"artifactory,omitempty"`
   556  	MissionControl *MissionControlDetails `json:"MissionControl,omitempty"`
   557  }
   558  
   559  func (o *ConfigV0) Convert() *ConfigV4 {
   560  	config := new(ConfigV4)
   561  	config.MissionControl = o.MissionControl
   562  	if o.Artifactory != nil {
   563  		o.Artifactory.IsDefault = true
   564  		o.Artifactory.ServerId = DefaultServerId
   565  		config.Artifactory = []*ServerDetails{o.Artifactory}
   566  	}
   567  	return config
   568  }
   569  
   570  type ServerDetails struct {
   571  	Url                             string `json:"url,omitempty"`
   572  	SshUrl                          string `json:"-"`
   573  	ArtifactoryUrl                  string `json:"artifactoryUrl,omitempty"`
   574  	DistributionUrl                 string `json:"distributionUrl,omitempty"`
   575  	XrayUrl                         string `json:"xrayUrl,omitempty"`
   576  	XscUrl                          string `json:"xscUrl,omitempty"`
   577  	MissionControlUrl               string `json:"missionControlUrl,omitempty"`
   578  	PipelinesUrl                    string `json:"pipelinesUrl,omitempty"`
   579  	AccessUrl                       string `json:"accessUrl,omitempty"`
   580  	LifecycleUrl                    string `json:"-"`
   581  	User                            string `json:"user,omitempty"`
   582  	Password                        string `json:"password,omitempty"`
   583  	SshKeyPath                      string `json:"sshKeyPath,omitempty"`
   584  	SshPassphrase                   string `json:"sshPassphrase,omitempty"`
   585  	AccessToken                     string `json:"accessToken,omitempty"`
   586  	RefreshToken                    string `json:"refreshToken,omitempty"`
   587  	ArtifactoryRefreshToken         string `json:"artifactoryRefreshToken,omitempty"`
   588  	ArtifactoryTokenRefreshInterval int    `json:"tokenRefreshInterval,omitempty"`
   589  	ClientCertPath                  string `json:"clientCertPath,omitempty"`
   590  	ClientCertKeyPath               string `json:"clientCertKeyPath,omitempty"`
   591  	ServerId                        string `json:"serverId,omitempty"`
   592  	IsDefault                       bool   `json:"isDefault,omitempty"`
   593  	InsecureTls                     bool   `json:"-"`
   594  	WebLogin                        bool   `json:"webLogin,omitempty"`
   595  }
   596  
   597  // Deprecated
   598  type MissionControlDetails struct {
   599  	Url         string `json:"url,omitempty"`
   600  	AccessToken string `json:"accessToken,omitempty"`
   601  }
   602  
   603  func (serverDetails *ServerDetails) IsEmpty() bool {
   604  	return len(serverDetails.ServerId) == 0 && serverDetails.Url == ""
   605  }
   606  
   607  func (serverDetails *ServerDetails) SetUser(username string) {
   608  	serverDetails.User = username
   609  }
   610  
   611  func (serverDetails *ServerDetails) SetPassword(password string) {
   612  	serverDetails.Password = password
   613  }
   614  
   615  func (serverDetails *ServerDetails) SetAccessToken(accessToken string) {
   616  	serverDetails.AccessToken = accessToken
   617  }
   618  
   619  func (serverDetails *ServerDetails) SetArtifactoryRefreshToken(refreshToken string) {
   620  	serverDetails.ArtifactoryRefreshToken = refreshToken
   621  }
   622  
   623  func (serverDetails *ServerDetails) SetRefreshToken(refreshToken string) {
   624  	serverDetails.RefreshToken = refreshToken
   625  }
   626  
   627  func (serverDetails *ServerDetails) SetSshPassphrase(sshPassphrase string) {
   628  	serverDetails.SshPassphrase = sshPassphrase
   629  }
   630  
   631  func (serverDetails *ServerDetails) SetClientCertPath(certificatePath string) {
   632  	serverDetails.ClientCertPath = certificatePath
   633  }
   634  
   635  func (serverDetails *ServerDetails) SetClientCertKeyPath(certificatePath string) {
   636  	serverDetails.ClientCertKeyPath = certificatePath
   637  }
   638  
   639  func (serverDetails *ServerDetails) GetUrl() string {
   640  	return serverDetails.Url
   641  }
   642  
   643  func (serverDetails *ServerDetails) GetArtifactoryUrl() string {
   644  	return serverDetails.ArtifactoryUrl
   645  }
   646  
   647  func (serverDetails *ServerDetails) GetDistributionUrl() string {
   648  	return serverDetails.DistributionUrl
   649  }
   650  
   651  func (serverDetails *ServerDetails) GetXrayUrl() string {
   652  	return serverDetails.XrayUrl
   653  }
   654  
   655  func (serverDetails *ServerDetails) GetMissionControlUrl() string {
   656  	return serverDetails.MissionControlUrl
   657  }
   658  
   659  func (serverDetails *ServerDetails) GetPipelinesUrl() string {
   660  	return serverDetails.PipelinesUrl
   661  }
   662  
   663  func (serverDetails *ServerDetails) GetAccessUrl() string {
   664  	return serverDetails.AccessUrl
   665  }
   666  
   667  func (serverDetails *ServerDetails) GetLifecycleUrl() string {
   668  	return serverDetails.LifecycleUrl
   669  }
   670  
   671  func (serverDetails *ServerDetails) GetUser() string {
   672  	return serverDetails.User
   673  }
   674  
   675  func (serverDetails *ServerDetails) GetPassword() string {
   676  	return serverDetails.Password
   677  }
   678  
   679  func (serverDetails *ServerDetails) GetAccessToken() string {
   680  	return serverDetails.AccessToken
   681  }
   682  
   683  func (serverDetails *ServerDetails) GetRefreshToken() string {
   684  	return serverDetails.RefreshToken
   685  }
   686  
   687  func (serverDetails *ServerDetails) GetClientCertPath() string {
   688  	return serverDetails.ClientCertPath
   689  }
   690  
   691  func (serverDetails *ServerDetails) GetClientCertKeyPath() string {
   692  	return serverDetails.ClientCertKeyPath
   693  }
   694  
   695  func (serverDetails *ServerDetails) CreateArtAuthConfig() (auth.ServiceDetails, error) {
   696  	artAuth := artifactoryAuth.NewArtifactoryDetails()
   697  	artAuth.SetUrl(serverDetails.ArtifactoryUrl)
   698  	return serverDetails.createAuthConfig(artAuth)
   699  }
   700  
   701  func (serverDetails *ServerDetails) CreateDistAuthConfig() (auth.ServiceDetails, error) {
   702  	artAuth := distributionAuth.NewDistributionDetails()
   703  	artAuth.SetUrl(serverDetails.DistributionUrl)
   704  	return serverDetails.createAuthConfig(artAuth)
   705  }
   706  
   707  func (serverDetails *ServerDetails) CreateXrayAuthConfig() (auth.ServiceDetails, error) {
   708  	artAuth := xrayAuth.NewXrayDetails()
   709  	artAuth.SetUrl(serverDetails.XrayUrl)
   710  	return serverDetails.createAuthConfig(artAuth)
   711  }
   712  
   713  func (serverDetails *ServerDetails) CreateXscAuthConfig() (auth.ServiceDetails, error) {
   714  	ascAuth := xscAuth.NewXscDetails()
   715  	ascAuth.SetUrl(serverDetails.convertXrayUrlToXscUrl())
   716  	return serverDetails.createAuthConfig(ascAuth)
   717  }
   718  
   719  // Xray and Xsc will always have the same platform url.
   720  func (serverDetails *ServerDetails) convertXrayUrlToXscUrl() string {
   721  	xscUrl := strings.TrimSuffix(serverDetails.XrayUrl, "/")
   722  	xscUrl = strings.TrimSuffix(xscUrl, "/xray")
   723  	return xscUrl + "/xsc/"
   724  }
   725  
   726  func (serverDetails *ServerDetails) CreatePipelinesAuthConfig() (auth.ServiceDetails, error) {
   727  	pAuth := pipelinesAuth.NewPipelinesDetails()
   728  	pAuth.SetUrl(serverDetails.PipelinesUrl)
   729  	return serverDetails.createAuthConfig(pAuth)
   730  }
   731  
   732  func (serverDetails *ServerDetails) CreateAccessAuthConfig() (auth.ServiceDetails, error) {
   733  	pAuth := accessAuth.NewAccessDetails()
   734  	pAuth.SetUrl(utils.AddTrailingSlashIfNeeded(serverDetails.Url) + "access/")
   735  	return serverDetails.createAuthConfig(pAuth)
   736  }
   737  
   738  func (serverDetails *ServerDetails) CreateLifecycleAuthConfig() (auth.ServiceDetails, error) {
   739  	lcAuth := lifecycleAuth.NewLifecycleDetails()
   740  	lcAuth.SetUrl(serverDetails.LifecycleUrl)
   741  	return serverDetails.createAuthConfig(lcAuth)
   742  }
   743  
   744  func (serverDetails *ServerDetails) createAuthConfig(details auth.ServiceDetails) (auth.ServiceDetails, error) {
   745  	details.SetSshUrl(serverDetails.SshUrl)
   746  	details.SetAccessToken(serverDetails.AccessToken)
   747  	// If refresh token is not empty, set a refresh handler and skip other credentials.
   748  	// First we check access's token, if empty we check artifactory's token.
   749  	switch {
   750  	case serverDetails.RefreshToken != "":
   751  		// Save serverId for refreshing if needed. If empty serverId is saved, default will be used.
   752  		tokenRefreshServerId = serverDetails.ServerId
   753  		details.AppendPreRequestFunction(AccessTokenRefreshPreRequestInterceptor)
   754  	case serverDetails.ArtifactoryRefreshToken != "":
   755  		// Save serverId for refreshing if needed. If empty serverId is saved, default will be used.
   756  		tokenRefreshServerId = serverDetails.ServerId
   757  		details.AppendPreRequestFunction(ArtifactoryTokenRefreshPreRequestInterceptor)
   758  	default:
   759  		details.SetUser(serverDetails.User)
   760  		details.SetPassword(serverDetails.Password)
   761  	}
   762  	details.SetClientCertPath(serverDetails.ClientCertPath)
   763  	details.SetClientCertKeyPath(serverDetails.ClientCertKeyPath)
   764  	details.SetSshKeyPath(serverDetails.SshKeyPath)
   765  	details.SetSshPassphrase(serverDetails.SshPassphrase)
   766  	return details, nil
   767  }
   768  
   769  // GetAuthenticationCredentials retrieves authentication credentials for the serverDetails instance.
   770  // If both a username and password are provided, they are returned.
   771  // If only an access token is provided, the function extracts the username from the access token,
   772  // and both the username and access token are returned.
   773  //
   774  // Returns:
   775  // - Username and password if both are provided.
   776  // - Username extracted from the access token, along with the access token, if the access token is provided.
   777  // - An error if neither username/password nor access token is provided, with details about the missing credentials.
   778  func (serverDetails *ServerDetails) GetAuthenticationCredentials() (string, string, error) {
   779  	// Username and password are set
   780  	if serverDetails.Password != "" && serverDetails.User != "" {
   781  		return serverDetails.User, serverDetails.Password, nil
   782  	}
   783  
   784  	// Access token is set, extract the username from the access token if needed
   785  	if serverDetails.AccessToken != "" {
   786  		if serverDetails.User == "" {
   787  			serverDetails.User = auth.ExtractUsernameFromAccessToken(serverDetails.AccessToken)
   788  		}
   789  		return serverDetails.User, serverDetails.AccessToken, nil
   790  	}
   791  
   792  	// Username/Password or Access token isn't set
   793  	errMissingCredsMsg := "either username/password or access token must be set for "
   794  	if serverDetails.Url != "" {
   795  		errMissingCredsMsg += serverDetails.Url
   796  	} else if serverDetails.ArtifactoryUrl != "" {
   797  		errMissingCredsMsg += serverDetails.ArtifactoryUrl
   798  	}
   799  	return "", "", errorutils.CheckErrorf(errMissingCredsMsg)
   800  }
   801  
   802  func (missionControlDetails *MissionControlDetails) GetAccessToken() string {
   803  	return missionControlDetails.AccessToken
   804  }
   805  
   806  func (missionControlDetails *MissionControlDetails) SetAccessToken(accessToken string) {
   807  	missionControlDetails.AccessToken = accessToken
   808  }