diff --git a/auth_providers/auth_basic.go b/auth_providers/auth_basic.go index e36d427..7e6ee5a 100644 --- a/auth_providers/auth_basic.go +++ b/auth_providers/auth_basic.go @@ -255,6 +255,7 @@ func (a *CommandAuthConfigBasic) GetServerConfig() *Server { SkipTLSVerify: a.SkipVerify, CACertPath: a.CommandCACert, AuthType: "basic", + ClientTimeout: a.HttpClientTimeout, } return &server } diff --git a/auth_providers/auth_core.go b/auth_providers/auth_core.go index c2ca07d..6528463 100644 --- a/auth_providers/auth_core.go +++ b/auth_providers/auth_core.go @@ -170,7 +170,28 @@ func cleanHostName(hostName string) string { return hostName } +// parseHostPort splits a "hostname:port" string into its parts. +// If no port is present, returns the hostname and 0. +func parseHostPort(hostName string) (string, int) { + if idx := strings.LastIndex(hostName, ":"); idx != -1 { + portStr := hostName[idx+1:] + port := 0 + for _, c := range portStr { + if c < '0' || c > '9' { + return hostName, 0 + } + port = port*10 + int(c-'0') + } + if port > 0 { + return hostName[:idx], port + } + } + return hostName, 0 +} + // WithCommandHostName sets the hostname for authentication to Keyfactor Command API. +// If hostName contains a port (e.g. "host:9443"), the port is extracted and applied +// via WithCommandPort so the SDK does not double-append a port to the URL. func (c *CommandAuthConfig) WithCommandHostName(hostName string) *CommandAuthConfig { //check for http or https prefix @@ -179,7 +200,13 @@ func (c *CommandAuthConfig) WithCommandHostName(hostName string) *CommandAuthCon } hostName = cleanHostName(hostName) - c.CommandHostName = hostName + host, port := parseHostPort(hostName) + if port > 0 { + c.CommandHostName = host + c.CommandPort = port + } else { + c.CommandHostName = hostName + } return c } @@ -485,11 +512,14 @@ func (c *CommandAuthConfig) Authenticate() error { headers["Authorization"] = c.AuthHeader } + authHost := c.CommandHostName + if c.CommandPort > 0 && c.CommandPort != DefaultCommandPort { + authHost = fmt.Sprintf("%s:%d", c.CommandHostName, c.CommandPort) + } endPoint := fmt.Sprintf( "%s://%s/%s/Status/Endpoints", c.HttpProtocol, - c.CommandHostName, - //c.CommandPort, + authHost, c.CommandAPIPath, ) log.Printf("[DEBUG] testing auth using endpoint %s ", endPoint) @@ -763,6 +793,7 @@ func (c *CommandAuthConfig) GetServerConfig() *Server { SkipTLSVerify: c.SkipVerify, CACertPath: c.CommandCACert, AuthType: "", + ClientTimeout: c.HttpClientTimeout, } return &server } diff --git a/auth_providers/auth_kerberos.go b/auth_providers/auth_kerberos.go index 9a83f54..7d969ec 100644 --- a/auth_providers/auth_kerberos.go +++ b/auth_providers/auth_kerberos.go @@ -443,6 +443,7 @@ func (k *CommandAuthConfigKerberos) GetServerConfig() *Server { SkipTLSVerify: k.SkipVerify, CACertPath: k.CommandCACert, AuthType: "kerberos", + ClientTimeout: k.HttpClientTimeout, KerberosRealm: k.Realm, KerberosKeytab: k.KeytabPath, KerberosConfig: k.ConfigPath, diff --git a/auth_providers/auth_oauth.go b/auth_providers/auth_oauth.go index d402b75..8c3243b 100644 --- a/auth_providers/auth_oauth.go +++ b/auth_providers/auth_oauth.go @@ -436,6 +436,7 @@ func (b *CommandConfigOauth) GetServerConfig() *Server { SkipTLSVerify: b.SkipVerify, CACertPath: b.CommandCACert, AuthType: "oauth", + ClientTimeout: b.HttpClientTimeout, } return &server } diff --git a/auth_providers/command_config.go b/auth_providers/command_config.go index e8a14a3..336858d 100644 --- a/auth_providers/command_config.go +++ b/auth_providers/command_config.go @@ -41,6 +41,11 @@ type Server struct { CACertPath string `json:"ca_cert_path,omitempty" yaml:"ca_cert_path,omitempty"` // CACertPath is the path to the CA certificate to trust. AuthType string `json:"auth_type,omitempty" yaml:"auth_type,omitempty"` // AuthType is the type of authentication to use. + // ClientTimeout is the HTTP client timeout in seconds. When zero, kfc-auth + // falls back to the KEYFACTOR_CLIENT_TIMEOUT env var or a built-in + // default. Maps to CommandAuthConfig.HttpClientTimeout. + ClientTimeout int `json:"client_timeout,omitempty" yaml:"client_timeout,omitempty"` + // Kerberos authentication fields KerberosRealm string `json:"kerberos_realm,omitempty" yaml:"kerberos_realm,omitempty"` // KerberosRealm is the Kerberos realm (uppercase). KerberosKeytab string `json:"kerberos_keytab,omitempty" yaml:"kerberos_keytab,omitempty"` // KerberosKeytab is the path to the keytab file.