Skip to content

Commit

Permalink
parser for auth params
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Wozniak <wozniak.jan@gmail.com>
  • Loading branch information
wozniakjan committed May 8, 2024
1 parent 0cf6cd0 commit a80d471
Show file tree
Hide file tree
Showing 5 changed files with 613 additions and 93 deletions.
128 changes: 128 additions & 0 deletions pkg/scalers/authentication/authentication_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package authentication

import (
"fmt"
"net/url"
"time"
)
Expand Down Expand Up @@ -31,6 +32,8 @@ const (
FastHTTP // FastHTTP Fast http client.
)

// AuthMeta is the metadata for the authentication types
// Deprecated: use Config instead
type AuthMeta struct {
// bearer auth
EnableBearerAuth bool
Expand Down Expand Up @@ -61,6 +64,131 @@ type AuthMeta struct {
CustomAuthValue string
}

// BasicAuth is a basic authentication type
type BasicAuth struct {
Username string `keda:"name=username, parsingOrder=authParams"`
Password string `keda:"name=password, parsingOrder=authParams"`
}

// CertAuth is a client certificate authentication type
type CertAuth struct {
Cert string `keda:"name=cert, parsingOrder=authParams"`
Key string `keda:"name=key, parsingOrder=authParams"`
CA string `keda:"name=ca, parsingOrder=authParams"`
}

// OAuth is an oAuth2 authentication type
type OAuth struct {
OauthTokenURI string `keda:"name=oauthTokenURI, parsingOrder=authParams"`
Scopes []string `keda:"name=scopes, parsingOrder=authParams"`
ClientID string `keda:"name=clientID, parsingOrder=authParams"`
ClientSecret string `keda:"name=clientSecret, parsingOrder=authParams"`
EndpointParams url.Values `keda:"name=endpointParams, parsingOrder=authParams"`
}

// CustomAuth is a custom header authentication type
type CustomAuth struct {
CustomAuthHeader string `keda:"name=customAuthHeader, parsingOrder=authParams"`
CustomAuthValue string `keda:"name=customAuthValue, parsingOrder=authParams"`
}

// Config is the configuration for the authentication types
type Config struct {
Modes []Type `keda:"name=authModes, parsingOrder=triggerMetadata, enum=apiKey;basic;tls;bearer;custom;oauth, exclusive=bearer;basic;oauth, optional"`

BearerToken string `keda:"name=bearerToken, parsingOrder=authParams, optional"`
BasicAuth `keda:"optional"`
CertAuth `keda:"optional"`
OAuth `keda:"optional"`
CustomAuth `keda:"optional"`
}

// Disabled returns true if no auth modes are enabled
func (c *Config) Disabled() bool {
return c == nil || len(c.Modes) == 0
}

// Enabled returns true if given auth mode is enabled
func (c *Config) Enabled(mode Type) bool {
for _, m := range c.Modes {
if m == mode {
return true
}
}
return false
}

// helpers for checking enabled auth modes
func (c *Config) EnabledTLS() bool { return c.Enabled(TLSAuthType) }
func (c *Config) EnabledBasicAuth() bool { return c.Enabled(BasicAuthType) }
func (c *Config) EnabledBearerAuth() bool { return c.Enabled(BearerAuthType) }
func (c *Config) EnabledOAuth() bool { return c.Enabled(OAuthType) }
func (c *Config) EnabledCustomAuth() bool { return c.Enabled(CustomAuthType) }

// GetBearerToken returns the bearer token with the Bearer prefix
func (c *Config) GetBearerToken() string {
return fmt.Sprintf("Bearer %s", c.BearerToken)
}

// Validate validates the Config and returns an error if it is invalid
func (c *Config) Validate() error {
if c.Disabled() {
return nil
}
if c.EnabledBearerAuth() && c.BearerToken == "" {
return fmt.Errorf("bearer token is required when bearer auth is enabled")
}
if c.EnabledBasicAuth() && c.Username == "" {
return fmt.Errorf("username is required when basic auth is enabled")
}
if c.EnabledTLS() && (c.Cert == "" || c.Key == "") {
return fmt.Errorf("cert and key are required when tls auth is enabled")
}
if c.EnabledOAuth() && (c.OauthTokenURI == "" || c.ClientID == "" || c.ClientSecret == "") {
return fmt.Errorf("oauthTokenURI, clientID and clientSecret are required when oauth is enabled")
}
if c.EnabledCustomAuth() && (c.CustomAuthHeader == "" || c.CustomAuthValue == "") {
return fmt.Errorf("customAuthHeader and customAuthValue are required when custom auth is enabled")
}
return nil
}

// ToAuthMeta converts the Config to deprecated AuthMeta
func (c *Config) ToAuthMeta() *AuthMeta {
if c.Disabled() {
return nil
}
return &AuthMeta{
// bearer auth
EnableBearerAuth: c.EnabledBearerAuth(),
BearerToken: c.BearerToken,

// basic auth
EnableBasicAuth: c.EnabledBasicAuth(),
Username: c.Username,
Password: c.Password,

// client certification
EnableTLS: c.EnabledTLS(),
Cert: c.Cert,
Key: c.Key,
CA: c.CA,

// oAuth2
EnableOAuth: c.EnabledOAuth(),
OauthTokenURI: c.OauthTokenURI,
Scopes: c.Scopes,
ClientID: c.ClientID,
ClientSecret: c.ClientSecret,
EndpointParams: c.EndpointParams,

// custom auth header
EnableCustomAuth: c.EnabledCustomAuth(),
CustomAuthHeader: c.CustomAuthHeader,
CustomAuthValue: c.CustomAuthValue,
}
}

type HTTPTransport struct {
MaxIdleConnDuration time.Duration
ReadTimeout time.Duration
Expand Down
63 changes: 30 additions & 33 deletions pkg/scalers/prometheus_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,21 @@ type prometheusScaler struct {
// change to false/f if can not accept prometheus return null values
// https://github.com/kedacore/keda/issues/3065
type prometheusMetadata struct {
prometheusAuth *authentication.AuthMeta
triggerIndex int

ServerAddress string `keda:"name=serverAddress, parsingOrder=triggerMetadata"`
Query string `keda:"name=query, parsingOrder=triggerMetadata"`
QueryParameters map[string]string `keda:"name=queryParameters, parsingOrder=triggerMetadata, optional"`
Threshold float64 `keda:"name=threshold, parsingOrder=triggerMetadata"`
ActivationThreshold float64 `keda:"name=activationThreshold, parsingOrder=triggerMetadata, optional"`
Namespace string `keda:"name=namespace, parsingOrder=triggerMetadata, optional"`
CustomHeaders map[string]string `keda:"name=customHeaders, parsingOrder=triggerMetadata, optional"`
IgnoreNullValues bool `keda:"name=ignoreNullValues, parsingOrder=triggerMetadata, optional, default=true"`
UnsafeSSL bool `keda:"name=unsafeSsl, parsingOrder=triggerMetadata, optional"`
CortexOrgID string `keda:"name=cortexOrgID, parsingOrder=triggerMetadata, optional, deprecated=use customHeaders instead"`
triggerIndex int

PrometheusAuth *authentication.Config `keda:"optional"`
ServerAddress string `keda:"name=serverAddress, parsingOrder=triggerMetadata"`
Query string `keda:"name=query, parsingOrder=triggerMetadata"`
QueryParameters map[string]string `keda:"name=queryParameters, parsingOrder=triggerMetadata, optional"`
Threshold float64 `keda:"name=threshold, parsingOrder=triggerMetadata"`
ActivationThreshold float64 `keda:"name=activationThreshold, parsingOrder=triggerMetadata, optional"`
Namespace string `keda:"name=namespace, parsingOrder=triggerMetadata, optional"`
CustomHeaders map[string]string `keda:"name=customHeaders, parsingOrder=triggerMetadata, optional"`
IgnoreNullValues bool `keda:"name=ignoreNullValues, parsingOrder=triggerMetadata, optional, default=true"`
UnsafeSSL bool `keda:"name=unsafeSsl, parsingOrder=triggerMetadata, optional"`

// deprecated
CortexOrgID string `keda:"name=cortexOrgID, parsingOrder=triggerMetadata, optional, deprecated=use customHeaders instead"`
}

type promQueryResult struct {
Expand Down Expand Up @@ -93,12 +95,12 @@ func NewPrometheusScaler(config *scalersconfig.ScalerConfig) (Scaler, error) {

httpClient := kedautil.CreateHTTPClient(config.GlobalHTTPTimeout, meta.UnsafeSSL)

if meta.prometheusAuth != nil {
if meta.prometheusAuth.CA != "" || meta.prometheusAuth.EnableTLS {
if !meta.PrometheusAuth.Disabled() {
if meta.PrometheusAuth.CA != "" || meta.PrometheusAuth.EnabledTLS() {
// create http.RoundTripper with auth settings from ScalerConfig
transport, err := authentication.CreateHTTPRoundTripper(
authentication.NetHTTP,
meta.prometheusAuth,
meta.PrometheusAuth.ToAuthMeta(),
)
if err != nil {
logger.V(1).Error(err, "init Prometheus client http transport")
Expand Down Expand Up @@ -156,26 +158,21 @@ func parsePrometheusMetadata(config *scalersconfig.ScalerConfig) (meta *promethe
}

meta.triggerIndex = config.TriggerIndex
err = parseAuthConfig(config, meta)
err = checkAuthConfigWithPodIdentity(config, meta)
if err != nil {
return nil, err
}

return meta, nil
}

func parseAuthConfig(config *scalersconfig.ScalerConfig, meta *prometheusMetadata) error {
// parse auth configs from ScalerConfig
auth, err := authentication.GetAuthConfigs(config.TriggerMetadata, config.AuthParams)
if err != nil {
return err
func checkAuthConfigWithPodIdentity(config *scalersconfig.ScalerConfig, meta *prometheusMetadata) error {
if meta == nil || meta.PrometheusAuth.Disabled() {
return nil
}

if auth != nil && !(config.PodIdentity.Provider == kedav1alpha1.PodIdentityProviderNone || config.PodIdentity.Provider == "") {
if !(config.PodIdentity.Provider == kedav1alpha1.PodIdentityProviderNone || config.PodIdentity.Provider == "") {
return fmt.Errorf("pod identity cannot be enabled with other auth types")
}
meta.prometheusAuth = auth

return nil
}

Expand Down Expand Up @@ -226,14 +223,14 @@ func (s *prometheusScaler) ExecutePromQuery(ctx context.Context) (float64, error
}

switch {
case s.metadata.prometheusAuth == nil:
case s.metadata.PrometheusAuth.Disabled():
break
case s.metadata.prometheusAuth.EnableBearerAuth:
req.Header.Set("Authorization", authentication.GetBearerToken(s.metadata.prometheusAuth))
case s.metadata.prometheusAuth.EnableBasicAuth:
req.SetBasicAuth(s.metadata.prometheusAuth.Username, s.metadata.prometheusAuth.Password)
case s.metadata.prometheusAuth.EnableCustomAuth:
req.Header.Set(s.metadata.prometheusAuth.CustomAuthHeader, s.metadata.prometheusAuth.CustomAuthValue)
case s.metadata.PrometheusAuth.EnabledBearerAuth():
req.Header.Set("Authorization", s.metadata.PrometheusAuth.GetBearerToken())
case s.metadata.PrometheusAuth.EnabledBasicAuth():
req.SetBasicAuth(s.metadata.PrometheusAuth.Username, s.metadata.PrometheusAuth.Password)
case s.metadata.PrometheusAuth.EnabledCustomAuth():
req.Header.Set(s.metadata.PrometheusAuth.CustomAuthHeader, s.metadata.PrometheusAuth.CustomAuthValue)
}

r, err := s.httpClient.Do(req)
Expand Down
10 changes: 5 additions & 5 deletions pkg/scalers/prometheus_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ func TestPrometheusScalerAuthParams(t *testing.T) {
}

if err == nil {
if meta.prometheusAuth != nil {
if (meta.prometheusAuth.EnableBearerAuth && !strings.Contains(testData.metadata["authModes"], "bearer")) ||
(meta.prometheusAuth.EnableBasicAuth && !strings.Contains(testData.metadata["authModes"], "basic")) ||
(meta.prometheusAuth.EnableTLS && !strings.Contains(testData.metadata["authModes"], "tls")) ||
(meta.prometheusAuth.EnableCustomAuth && !strings.Contains(testData.metadata["authModes"], "custom")) {
if !meta.PrometheusAuth.Disabled() {
if (meta.PrometheusAuth.EnabledBearerAuth() && !strings.Contains(testData.metadata["authModes"], "bearer")) ||
(meta.PrometheusAuth.EnabledBasicAuth() && !strings.Contains(testData.metadata["authModes"], "basic")) ||
(meta.PrometheusAuth.EnabledTLS() && !strings.Contains(testData.metadata["authModes"], "tls")) ||
(meta.PrometheusAuth.EnabledCustomAuth() && !strings.Contains(testData.metadata["authModes"], "custom")) {
t.Error("wrong auth mode detected")
}
}
Expand Down
Loading

0 comments on commit a80d471

Please sign in to comment.