mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-23 03:29:51 +02:00
proxy: add JWT request signing support (#19)
- Refactored middleware and request hander logging. - Request refactored to use context.Context. - Add helper (based on Alice) to allow middleware chaining. - Add helper scripts to generate elliptic curve self-signed certificate that can be used to sign JWT. - Changed LetsEncrypt scripts to use acme instead of certbot. - Add script to have LetsEncrypt sign an RSA based certificate. - Add documentation to explain how to verify headers. - Refactored internal/cryptutil signer's code to expect a valid EC priv key. - Changed JWT expiries to use default leeway period. - Update docs and add screenshots. - Replaced logging handler logic to use context.Context. - Removed specific XML error handling. - Refactored handler function signatures to prefer standard go idioms.
This commit is contained in:
parent
98b8c7481f
commit
426e003b03
30 changed files with 1711 additions and 588 deletions
122
internal/cryptutil/marshal_test.go
Normal file
122
internal/cryptutil/marshal_test.go
Normal file
|
@ -0,0 +1,122 @@
|
|||
package cryptutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A keypair for NIST P-256 / secp256r1
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name prime256v1 -outform PEM
|
||||
var pemECPrivateKeyP256 = `-----BEGIN EC PARAMETERS-----
|
||||
BggqhkjOPQMBBw==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIOI+EZsjyN3jvWJI/KDihFmqTuDpUe/if6f/pgGTBta/oAoGCCqGSM49
|
||||
AwEHoUQDQgAEhhObKJ1r1PcUw+3REd/TbmSZnDvXnFUSTwqQFo5gbfIlP+gvEYba
|
||||
+Rxj2hhqjfzqxIleRK40IRyEi3fJM/8Qhg==
|
||||
-----END EC PRIVATE KEY-----
|
||||
`
|
||||
|
||||
var pemECPublicKeyP256 = `-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEhhObKJ1r1PcUw+3REd/TbmSZnDvX
|
||||
nFUSTwqQFo5gbfIlP+gvEYba+Rxj2hhqjfzqxIleRK40IRyEi3fJM/8Qhg==
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
// A keypair for NIST P-384 / secp384r1
|
||||
// Generated using:
|
||||
// openssl ecparam -genkey -name secp384r1 -outform PEM
|
||||
var pemECPrivateKeyP384 = `-----BEGIN EC PARAMETERS-----
|
||||
BgUrgQQAIg==
|
||||
-----END EC PARAMETERS-----
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDAhA0YPVL1kimIy+FAqzUAtmR3It2Yjv2I++YpcC4oX7wGuEWcWKBYE
|
||||
oOjj7wG/memgBwYFK4EEACKhZANiAAQub8xaaCTTW5rCHJCqUddIXpvq/TxdwViH
|
||||
+tPEQQlJAJciXStM/aNLYA7Q1K1zMjYyzKSWz5kAh/+x4rXQ9Hlm3VAwCQDVVSjP
|
||||
bfiNOXKOWfmyrGyQ7fQfs+ro1lmjLjs=
|
||||
-----END EC PRIVATE KEY-----
|
||||
`
|
||||
|
||||
var pemECPublicKeyP384 = `-----BEGIN PUBLIC KEY-----
|
||||
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAELm/MWmgk01uawhyQqlHXSF6b6v08XcFY
|
||||
h/rTxEEJSQCXIl0rTP2jS2AO0NStczI2Msykls+ZAIf/seK10PR5Zt1QMAkA1VUo
|
||||
z234jTlyjln5sqxskO30H7Pq6NZZoy47
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
var garbagePEM = `-----BEGIN GARBAGE-----
|
||||
TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ=
|
||||
-----END GARBAGE-----
|
||||
`
|
||||
|
||||
func TestPublicKeyMarshaling(t *testing.T) {
|
||||
ecKey, err := DecodePublicKey([]byte(pemECPublicKeyP256))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pemBytes, _ := EncodePublicKey(ecKey)
|
||||
if !bytes.Equal(pemBytes, []byte(pemECPublicKeyP256)) {
|
||||
t.Fatal("public key encoding did not match")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPrivateKeyBadDecode(t *testing.T) {
|
||||
_, err := DecodePrivateKey([]byte(garbagePEM))
|
||||
if err == nil {
|
||||
t.Fatal("decoded garbage data without complaint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrivateKeyMarshaling(t *testing.T) {
|
||||
ecKey, err := DecodePrivateKey([]byte(pemECPrivateKeyP256))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pemBytes, _ := EncodePrivateKey(ecKey)
|
||||
if !strings.HasSuffix(pemECPrivateKeyP256, string(pemBytes)) {
|
||||
t.Fatal("private key encoding did not match")
|
||||
}
|
||||
}
|
||||
|
||||
// Test vector from https://tools.ietf.org/html/rfc7515#appendix-A.3.1
|
||||
var jwtTest = []struct {
|
||||
sigBytes []byte
|
||||
b64sig string
|
||||
}{
|
||||
{
|
||||
sigBytes: []byte{14, 209, 33, 83, 121, 99, 108, 72, 60, 47, 127, 21,
|
||||
88, 7, 212, 2, 163, 178, 40, 3, 58, 249, 124, 126, 23, 129, 154, 195, 22, 158,
|
||||
166, 101, 197, 10, 7, 211, 140, 60, 112, 229, 216, 241, 45, 175,
|
||||
8, 74, 84, 128, 166, 101, 144, 197, 242, 147, 80, 154, 143, 63, 127, 138, 131,
|
||||
163, 84, 213},
|
||||
b64sig: "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q",
|
||||
},
|
||||
}
|
||||
|
||||
func TestJWTEncoding(t *testing.T) {
|
||||
for _, tt := range jwtTest {
|
||||
result := EncodeSignatureJWT(tt.sigBytes)
|
||||
|
||||
if strings.Compare(result, tt.b64sig) != 0 {
|
||||
t.Fatalf("expected %s, got %s\n", tt.b64sig, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJWTDecoding(t *testing.T) {
|
||||
for _, tt := range jwtTest {
|
||||
resultSig, err := DecodeSignatureJWT(tt.b64sig)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(resultSig, tt.sigBytes) {
|
||||
t.Fatalf("decoded signature was incorrect")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue