Skip to content

Commit

Permalink
Refactor health server
Browse files Browse the repository at this point in the history
  • Loading branch information
bonzofenix committed Jul 2, 2024
1 parent b0829ec commit 3305ba9
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 81 deletions.
85 changes: 4 additions & 81 deletions src/autoscaler/healthendpoint/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ package healthendpoint
// - scheduler

import (
"net/http"
"net/http/pprof"
"time"

Expand All @@ -36,27 +35,9 @@ import (
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/crypto/bcrypt"
)

// basic authentication credentials struct
type basicAuthenticationMiddleware struct {
usernameHash []byte
passwordHash []byte
}

// middleware basic authentication middleware functionality for healthcheck
func (bam *basicAuthenticationMiddleware) middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, authOK := r.BasicAuth()

if !authOK || bcrypt.CompareHashAndPassword(bam.usernameHash, []byte(username)) != nil || bcrypt.CompareHashAndPassword(bam.passwordHash, []byte(password)) != nil {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}

func NewHealthRouter(conf helpers.HealthConfig, healthCheckers []Checker, logger lager.Logger, gatherer prometheus.Gatherer, time func() time.Time) (*mux.Router, error) {
var healthRouter *mux.Router
Expand All @@ -82,7 +63,7 @@ func NewHealthRouter(conf helpers.HealthConfig, healthCheckers []Checker, logger
}

func healthBasicAuthRouter(conf helpers.HealthConfig, healthCheckers []Checker, logger lager.Logger, gatherer prometheus.Gatherer, time func() time.Time) (*mux.Router, error) {
basicAuthentication, err := createBasicAuthMiddleware(logger, conf.HealthCheckUsernameHash, conf.HealthCheckUsername, conf.HealthCheckPasswordHash, conf.HealthCheckPassword)
ba, err := helpers.CreateBasicAuthMiddleware(logger, conf.HealthCheckUsernameHash, conf.HealthCheckUsername, conf.HealthCheckPasswordHash, conf.HealthCheckPassword)
if err != nil {
return nil, err
}
Expand All @@ -96,10 +77,9 @@ func healthBasicAuthRouter(conf helpers.HealthConfig, healthCheckers []Checker,
}
//authenticated paths
health := router.Path("/health").Subrouter()
health.Use(basicAuthentication.middleware)

health.Use(ba.BasicAuthenticationMiddleware)
pprofRouter := router.PathPrefix("/debug/pprof").Subrouter()
pprofRouter.Use(basicAuthentication.middleware)
pprofRouter.Use(ba.BasicAuthenticationMiddleware)

pprofRouter.HandleFunc("/cmdline", pprof.Cmdline)
pprofRouter.HandleFunc("/profile", pprof.Profile)
Expand All @@ -108,65 +88,8 @@ func healthBasicAuthRouter(conf helpers.HealthConfig, healthCheckers []Checker,
pprofRouter.PathPrefix("").HandlerFunc(pprof.Index)

everything := router.PathPrefix("").Subrouter()
everything.Use(basicAuthentication.middleware)
everything.Use(ba.BasicAuthenticationMiddleware)
everything.PathPrefix("").Handler(promHandler)

return router, nil
}

func createBasicAuthMiddleware(logger lager.Logger, usernameHash string, username string, passwordHash string, password string) (*basicAuthenticationMiddleware, error) {
usernameHashByte, err := getUserHashBytes(logger, usernameHash, username)
if err != nil {
return nil, err
}

passwordHashByte, err := getPasswordHashBytes(logger, passwordHash, password)
if err != nil {
return nil, err
}

basicAuthentication := &basicAuthenticationMiddleware{
usernameHash: usernameHashByte,
passwordHash: passwordHashByte,
}
return basicAuthentication, nil
}

func getPasswordHashBytes(logger lager.Logger, passwordHash string, password string) ([]byte, error) {
var passwordHashByte []byte
var err error
if passwordHash == "" {
if len(password) > 72 {
logger.Error("warning-configured-password-too-long-using-only-first-72-characters", bcrypt.ErrPasswordTooLong, lager.Data{"password-length": len(password)})
password = password[:72]
}
passwordHashByte, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost) // use MinCost as the config already provided it as cleartext
if err != nil {
logger.Error("failed-new-server-password", err)
return nil, err
}
} else {
passwordHashByte = []byte(passwordHash)
}
return passwordHashByte, nil
}

func getUserHashBytes(logger lager.Logger, usernameHash string, username string) ([]byte, error) {
var usernameHashByte []byte
var err error
if usernameHash == "" {
if len(username) > 72 {
logger.Error("warning-configured-username-too-long-using-only-first-72-characters", bcrypt.ErrPasswordTooLong, lager.Data{"username-length": len(username)})
username = username[:72]
}
// when username and password are set for health check
usernameHashByte, err = bcrypt.GenerateFromPassword([]byte(username), bcrypt.MinCost) // use MinCost as the config already provided it as cleartext
if err != nil {
logger.Error("failed-new-server-username", err)
return nil, err
}
} else {
usernameHashByte = []byte(usernameHash)
}
return usernameHashByte, err
}
83 changes: 83 additions & 0 deletions src/autoscaler/helpers/basic_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package helpers

import (
"net/http"

"code.cloudfoundry.org/lager/v3"
"golang.org/x/crypto/bcrypt"
)

type BasicAuthenticationMiddleware struct {
usernameHash []byte
passwordHash []byte
}

// middleware basic authentication middleware functionality for healthcheck
func (bam *BasicAuthenticationMiddleware) BasicAuthenticationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, authOK := r.BasicAuth()

if !authOK || bcrypt.CompareHashAndPassword(bam.usernameHash, []byte(username)) != nil || bcrypt.CompareHashAndPassword(bam.passwordHash, []byte(password)) != nil {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}

func CreateBasicAuthMiddleware(logger lager.Logger, usernameHash string, username string, passwordHash string, password string) (*BasicAuthenticationMiddleware, error) {
usernameHashByte, err := getUserHashBytes(logger, usernameHash, username)
if err != nil {
return nil, err
}

passwordHashByte, err := getPasswordHashBytes(logger, passwordHash, password)
if err != nil {
return nil, err
}

basicAuthentication := &BasicAuthenticationMiddleware{
usernameHash: usernameHashByte,
passwordHash: passwordHashByte,
}
return basicAuthentication, nil
}

func getUserHashBytes(logger lager.Logger, usernameHash string, username string) ([]byte, error) {
var usernameHashByte []byte
var err error
if usernameHash == "" {
if len(username) > 72 {
logger.Error("warning-configured-username-too-long-using-only-first-72-characters", bcrypt.ErrPasswordTooLong, lager.Data{"username-length": len(username)})
username = username[:72]
}
// when username and password are set for health check
usernameHashByte, err = bcrypt.GenerateFromPassword([]byte(username), bcrypt.MinCost) // use MinCost as the config already provided it as cleartext
if err != nil {
logger.Error("failed-new-server-username", err)
return nil, err
}
} else {
usernameHashByte = []byte(usernameHash)
}
return usernameHashByte, err
}

func getPasswordHashBytes(logger lager.Logger, passwordHash string, password string) ([]byte, error) {
var passwordHashByte []byte
var err error
if passwordHash == "" {
if len(password) > 72 {
logger.Error("warning-configured-password-too-long-using-only-first-72-characters", bcrypt.ErrPasswordTooLong, lager.Data{"password-length": len(password)})
password = password[:72]
}
passwordHashByte, err = bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost) // use MinCost as the config already provided it as cleartext
if err != nil {
logger.Error("failed-new-server-password", err)
return nil, err
}
} else {
passwordHashByte = []byte(passwordHash)
}
return passwordHashByte, nil
}

0 comments on commit 3305ba9

Please sign in to comment.