Skip to content

Commit 0215740

Browse files
authored
Merge pull request #9 from RealImage/decode-header
Decode url-encoded mtls leaf certificate header from AWS ALB
2 parents 02fd83d + 9212a1e commit 0215740

File tree

2 files changed

+22
-32
lines changed

2 files changed

+22
-32
lines changed

asgard/heimdallr.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
"encoding/pem"
1111
"log/slog"
1212
"net/http"
13+
"net/url"
1314

1415
"github.com/RealImage/bifrost"
1516
"github.com/google/uuid"
1617
)
1718

19+
const errBadAuthHeader = "missing or invalid authorization information, server is misconfigured"
20+
1821
type keyClientCert struct{}
1922

2023
// ClientCert returns the client certificate from the request context.
@@ -37,10 +40,21 @@ func Heimdallr(h HeaderName, ns uuid.UUID) func(http.Handler) http.Handler {
3740
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3841
ctx := r.Context()
3942

40-
certPEM := r.Header.Get(h.String())
41-
if certPEM == "" {
43+
certHeader := r.Header.Get(h.String())
44+
if certHeader == "" {
4245
slog.ErrorContext(ctx, "missing authorization header")
43-
http.Error(w, "missing authorization header", http.StatusUnauthorized)
46+
http.Error(w, errBadAuthHeader, http.StatusServiceUnavailable)
47+
return
48+
}
49+
50+
certPEM, err := url.PathUnescape(certHeader)
51+
if err != nil {
52+
slog.ErrorContext(
53+
ctx, "error decoding header",
54+
"headerName", h.String(),
55+
"headerValue", certHeader,
56+
)
57+
http.Error(w, errBadAuthHeader, http.StatusServiceUnavailable)
4458
return
4559
}
4660

@@ -51,14 +65,14 @@ func Heimdallr(h HeaderName, ns uuid.UUID) func(http.Handler) http.Handler {
5165
"headerName", h.String(),
5266
"headerValue", certPEM,
5367
)
54-
http.Error(w, "invalid authorization header", http.StatusUnauthorized)
68+
http.Error(w, errBadAuthHeader, http.StatusServiceUnavailable)
5569
return
5670
}
5771

5872
cert, err := bifrost.ParseCertificate(block.Bytes)
5973
if err != nil {
6074
slog.ErrorContext(ctx, "error parsing client certificate", "error", err)
61-
http.Error(w, "invalid authorization header", http.StatusUnauthorized)
75+
http.Error(w, errBadAuthHeader, http.StatusServiceUnavailable)
6276
return
6377
}
6478

asgard/heimdallr_test.go

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,43 +41,19 @@ var heimdallrTestCases = []struct {
4141
expectedNs uuid.UUID
4242
}{
4343
{
44-
headerValue: `-----BEGIN CERTIFICATE-----
45-
MIICCjCCAbCgAwIBAgIIH7lebxROSBQwCgYIKoZIzj0EAwIwXjEtMCsGA1UEAwwk
46-
ZWZlYmJmZGMtZWMwNi01NjNmLWI4ZjItYjM5M2I0MjBkNWFlMS0wKwYDVQQKDCQw
47-
MTg4MUM4Qy1FMkUxLTQ5NTAtOURFRS0zQTk1NThDNkM3NDEwIBcNMjQwMjE0MTkz
48-
MDM1WhgPMjEwOTExMTAyMzAwMDBaMF4xLTArBgNVBAoTJDAxODgxYzhjLWUyZTEt
49-
NDk1MC05ZGVlLTNhOTU1OGM2Yzc0MTEtMCsGA1UEAxMkYWUyZTg5ZDUtZGFiYi01
50-
YTE1LWJhOTAtZWZmYzgzZmI3NzY0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
51-
hEo7+i7dB9WnliZorIEWistXAgrHrtOz2rW0LaXIZcJNiEUAWkTzMFKrY0JZPVBo
52-
UEXgYGHhV7hc3Id/+X4H9qNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
53-
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUyi+UDUP7bQBmCVBM
54-
jB+jvMHvmPQwCgYIKoZIzj0EAwIDSAAwRQIgOzVtg9kWc0BRJB2/JVDGAdjp6ozZ
55-
5XuF6SBT/Xd57OoCIQDiAXXDOGBHEoNxSo+oz20OzretMmtk6htl0UU1bzL6Lw==
56-
-----END CERTIFICATE-----`,
44+
headerValue: "-----BEGIN%20CERTIFICATE-----%0AMIICCjCCAbCgAwIBAgIIH7lebxROSBQwCgYIKoZIzj0EAwIwXjEtMCsGA1UEAwwk%0AZWZlYmJmZGMtZWMwNi01NjNmLWI4ZjItYjM5M2I0MjBkNWFlMS0wKwYDVQQKDCQw%0AMTg4MUM4Qy1FMkUxLTQ5NTAtOURFRS0zQTk1NThDNkM3NDEwIBcNMjQwMjE0MTkz%0AMDM1WhgPMjEwOTExMTAyMzAwMDBaMF4xLTArBgNVBAoTJDAxODgxYzhjLWUyZTEt%0ANDk1MC05ZGVlLTNhOTU1OGM2Yzc0MTEtMCsGA1UEAxMkYWUyZTg5ZDUtZGFiYi01%0AYTE1LWJhOTAtZWZmYzgzZmI3NzY0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE%0AhEo7+i7dB9WnliZorIEWistXAgrHrtOz2rW0LaXIZcJNiEUAWkTzMFKrY0JZPVBo%0AUEXgYGHhV7hc3Id%2F+X4H9qNWMFQwDgYDVR0PAQH%2FBAQDAgWgMBMGA1UdJQQMMAoG%0ACCsGAQUFBwMCMAwGA1UdEwEB%2FwQCMAAwHwYDVR0jBBgwFoAUyi+UDUP7bQBmCVBM%0AjB+jvMHvmPQwCgYIKoZIzj0EAwIDSAAwRQIgOzVtg9kWc0BRJB2%2FJVDGAdjp6ozZ%0A5XuF6SBT%2FXd57OoCIQDiAXXDOGBHEoNxSo+oz20OzretMmtk6htl0UU1bzL6Lw==%0A-----END%20CERTIFICATE-----",
5745
expectedKey: testPubKey,
5846
expectedNs: uuid.MustParse("01881C8C-E2E1-4950-9DEE-3A9558C6C741"),
5947
expectedCode: http.StatusOK,
6048
},
6149
{
62-
headerValue: `-----BEGIN CERTIFICATE-----
63-
MIICCTCCAbCgAwIBAgIIUKQb43DFdCEwCgYIKoZIzj0EAwIwXjEtMCsGA1UEAwwk
64-
ZWZlYmJmZGMtZWMwNi01NjNmLWI4ZjItYjM5M2I0MjBkNWFlMS0wKwYDVQQKDCQw
65-
MTg4MUM4Qy1FMkUxLTQ5NTAtOURFRS0zQTk1NThDNkM3NDEwIBcNMjQwMjE0MTkz
66-
NDQwWhgPMjEwOTExMTAyMzAwMDBaMF4xLTArBgNVBAoTJDAxODgxYzhjLWUyZTEt
67-
NDk1MC05ZGVlLTNhOTU1OGM2Yzc0MTEtMCsGA1UEAxMkYWUyZTg5ZDUtZGFiYi01
68-
YTE1LWJhOTAtZWZmYzgzZmI3NzY0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
69-
hEo7+i7dB9WnliZorIEWistXAgrHrtOz2rW0LaXIZcJNiEUAWkTzMFKrY0JZPVBo
70-
UEXgYGHhV7hc3Id/+X4H9qNWMFQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
71-
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUyi+UDUP7bQBmCVBM
72-
jB+jvMHvmPQwCgYIKoZIzj0EAwIDRwAwRAIgREgMNY2MSwKL3YVMyzgI4h/0/0au
73-
cpzcvv0u+i6cXHYCIGNqQgPElDasZfpAqS50msAs7yeTtZvBb396sZ+ZgJtk
74-
-----END CERTIFICATE-----`,
50+
headerValue: "-----BEGIN%20CERTIFICATE-----%0AMIICCTCCAbCgAwIBAgIIUKQb43DFdCEwCgYIKoZIzj0EAwIwXjEtMCsGA1UEAwwk%0AZWZlYmJmZGMtZWMwNi01NjNmLWI4ZjItYjM5M2I0MjBkNWFlMS0wKwYDVQQKDCQw%0AMTg4MUM4Qy1FMkUxLTQ5NTAtOURFRS0zQTk1NThDNkM3NDEwIBcNMjQwMjE0MTkz%0ANDQwWhgPMjEwOTExMTAyMzAwMDBaMF4xLTArBgNVBAoTJDAxODgxYzhjLWUyZTEt%0ANDk1MC05ZGVlLTNhOTU1OGM2Yzc0MTEtMCsGA1UEAxMkYWUyZTg5ZDUtZGFiYi01%0AYTE1LWJhOTAtZWZmYzgzZmI3NzY0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE%0AhEo7+i7dB9WnliZorIEWistXAgrHrtOz2rW0LaXIZcJNiEUAWkTzMFKrY0JZPVBo%0AUEXgYGHhV7hc3Id%2F+X4H9qNWMFQwDgYDVR0PAQH%2FBAQDAgWgMBMGA1UdJQQMMAoG%0ACCsGAQUFBwMCMAwGA1UdEwEB%2FwQCMAAwHwYDVR0jBBgwFoAUyi+UDUP7bQBmCVBM%0AjB+jvMHvmPQwCgYIKoZIzj0EAwIDRwAwRAIgREgMNY2MSwKL3YVMyzgI4h%2F0%2F0au%0Acpzcvv0u+i6cXHYCIGNqQgPElDasZfpAqS50msAs7yeTtZvBb396sZ+ZgJtk%0A-----END%20CERTIFICATE-----",
7551
expectedNs: uuid.MustParse("b9289da7-8813-51ed-957b-b6bc5a4d6416"),
7652
expectedCode: http.StatusForbidden,
7753
},
7854
{
7955
headerValue: "invalid json",
80-
expectedCode: http.StatusUnauthorized,
56+
expectedCode: http.StatusServiceUnavailable,
8157
},
8258
}
8359

0 commit comments

Comments
 (0)