Skip to content

Commit

Permalink
feat: Implement earlyEncode for paths in HMAC encoding based on URL
Browse files Browse the repository at this point in the history
Co-Authored-By: Sebastián Vargas <[email protected]>
  • Loading branch information
achetronic and sebastocorp committed Oct 10, 2024
1 parent 7c8245d commit 8cfc0eb
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 9 deletions.
8 changes: 8 additions & 0 deletions api/config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ type HmacConfigT struct {
Type string `yaml:"type"`
EncryptionKey string `yaml:"encryptionKey"`
EncryptionAlgorithm string `yaml:"encryptionAlgorithm"`

//
Url HmacUrlConfigT `yaml:"url,omitempty"`
}

type HmacUrlConfigT struct {
EarlyEncode bool `yaml:"earlyEncode,omitempty"`
LowerEncode bool `yaml:"lowerEncode,omitempty"`
}

type ModifierConfigT struct {
Expand Down
2 changes: 1 addition & 1 deletion charts/doorkeeper/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type: application
description: >-
A Helm chart for Doorkeeper, a tiny HTTP server to be used as
external authentication service for Envoy
version: &chartVersion 0.3.0
version: &chartVersion 0.4.0
appVersion: *chartVersion
kubeVersion: ">=1.22.0-0"
home: https://github.com/freepik-company/doorkeeper
Expand Down
6 changes: 6 additions & 0 deletions docs/samples/doorkeeper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ hmac:
encryptionKey: "${ENVIRONMENT_VARIABLE_WITH_ENCRYPTION_KEY}"
encryptionAlgorithm: "sha256"

url:
# (Optional) Transforms special characters (including /) with %XX sequences as needed
# When lowerEncode is true, encoded chars will be lowercase (e.g. %2f instead of %2F)
earlyEncode: true
lowerEncode: true

# (Optional) List of modifiers to apply to the request before signing it
modifiers:

Expand Down
15 changes: 9 additions & 6 deletions internal/hmac/hmac.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ func generateHMAC(tokenDigest, encryptionKey, encryptionAlgorithm string) (token

// ValidateToken TODO
// token: exp={int}~hmac={hash}
func ValidateTokenUrl(token, encryptionKey, encryptionAlgorithm, url string) (isValid bool, err error) {
func ValidateTokenUrl(token, encryptionKey, encryptionAlgorithm, url string) (isValid bool, generatedHmac, receivedHmac string, err error) {
// split token to get tokenDigest and HMAC
tokenParts := strings.Split(token, "~hmac=")
if len(tokenParts) != 2 {
return isValid, err
return isValid, generatedHmac, receivedHmac, err
}
tokenDigest := fmt.Sprintf("%s~url=%s", tokenParts[0], url)
tokenHMAC := []byte(tokenParts[1])
Expand All @@ -64,22 +64,25 @@ func ValidateTokenUrl(token, encryptionKey, encryptionAlgorithm, url string) (is
exp, err := strconv.ParseInt(expPart, 10, 64)
if err != nil {
err = fmt.Errorf("invalid expiration time '%s'", expPart)
return isValid, err
return isValid, generatedHmac, receivedHmac, err
}

if time.Now().Unix() >= exp {
err = fmt.Errorf("token has expired")
return isValid, err
return isValid, generatedHmac, receivedHmac, err
}

// generate HMAC with your local encription key to compare
generatedHMAC, err := generateHMAC(tokenDigest, encryptionKey, encryptionAlgorithm)
if err != nil {
return isValid, err
return isValid, generatedHmac, receivedHmac, err
}

generatedHmac = string(generatedHMAC)
receivedHmac = string(tokenHMAC)

// compare given with generated HMAC
isValid = hmac.Equal(generatedHMAC, tokenHMAC)

return isValid, err
return isValid, generatedHmac, receivedHmac, err
}
21 changes: 19 additions & 2 deletions internal/httpserver/httpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"regexp"
"strings"

Expand All @@ -21,6 +22,10 @@ const (
resultDeniedBody = "Unauthorized"
)

var (
urlEncodeRegex = regexp.MustCompile(`%[0-9a-fA-F]{2}`)
)

type HttpServer struct {
*http.Server
}
Expand Down Expand Up @@ -103,11 +108,23 @@ func (s *HttpServer) handleRequest(response http.ResponseWriter, request *http.R
}

var valid bool
var generatedHmac, receivedHmac string
if globals.Application.Config.Auth.Type == "hmac" {
path := strings.Split(request.URL.Path, "?")[0]

if globals.Application.Config.Hmac.Type == "url" {
valid, err = hmac.ValidateTokenUrl(token, globals.Application.Config.Hmac.EncryptionKey,
if globals.Application.Config.Hmac.Url.EarlyEncode {
path = url.PathEscape(path)

if globals.Application.Config.Hmac.Url.LowerEncode {
path = urlEncodeRegex.ReplaceAllStringFunc(path, func(match string) string {
return strings.ToLower(match)
})
}
}

//
valid, generatedHmac, receivedHmac, err = hmac.ValidateTokenUrl(token, globals.Application.Config.Hmac.EncryptionKey,
globals.Application.Config.Hmac.EncryptionAlgorithm, path)
if err != nil {
err = fmt.Errorf("unable to validate token in request: %s", err.Error())
Expand All @@ -117,7 +134,7 @@ func (s *HttpServer) handleRequest(response http.ResponseWriter, request *http.R
}

if !valid {
err = fmt.Errorf("invalid token in request")
err = fmt.Errorf("invalid token in request {generatedHMAC:'%s', receivedHMAC:'%s'}", generatedHmac, receivedHmac)
return
}

Expand Down

0 comments on commit 8cfc0eb

Please sign in to comment.