Skip to content

Commit b16622c

Browse files
authored
Merge pull request #39 from agilezebra/1.2.10
allow rootCAs from pem file
2 parents 506016a + da845df commit b16622c

File tree

5 files changed

+70
-3
lines changed

5 files changed

+70
-3
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ experimental:
1919
plugins:
2020
jwt:
2121
moduleName: github.com/agilezebra/jwt-middleware
22-
version: v1.2.9
22+
version: v1.2.10
2323
```
2424
1b. or with command-line options:
2525
2626
```yaml
2727
command:
2828
...
2929
- "--experimental.plugins.jwt.modulename=github.com/agilezebra/jwt-middleware"
30-
- "--experimental.plugins.jwt.version=v1.2.9"
30+
- "--experimental.plugins.jwt.version=v1.2.10"
3131
```
3232
3333
2) Configure and activate the plugin as a middleware in your dynamic traefik config:
@@ -72,7 +72,7 @@ Name | Description
7272
`forwardToken` | Boolean indicating whether the token should be forwarded to the backend. Default true. If multiple tokens are present in different locations (e.g. cookie and header) and forwarding is false, only the token used will be removed.
7373
`optional` | Validate tokens according to the normal rules but don't require that a token be present. If specific claim requirements are specified in `require` but with `optional` set to `true` and a token is not present, access will be permitted even though the requirements are obviously not met, which may not be what you want or expect. In this case, no headers will be set from claims (as there aren't any). This is quite a niche case but is intended for use on endpoints that support both authorized and anonymous access and you want JWTs verified if present.
7474
`insecureSkipVerify` | A list of issuers' domains for which TLS certificates should not be verified (i.e. use `InsecureSkipVerify: true`). Only the hostname/domain should be specified (i.e. no scheme or trailing slash). Applies to both the openid-configuration and jwks calls.
75-
`rootCAs` | One or more additional root certificate authorities, in PEM format, to be combined with the system cert pool when verifying server certificates.
75+
`rootCAs` | One or more additional root certificate authorities, each expressed either inline in PEM format, or as a path to a file, to be combined with the system cert pool when verifying server certificates.
7676
`infoToStdout` | traefik does not yet have support for plugins to use the logger so, by default, all messages are logged using `log.Printf`, which will send messages from the plugin out as if they were logged at `ERROR` level. This may be irritating for those that don't like to see non-error messages show up as if they are errors. There is a workaround available in that the plugin can send messages to STDOUT and traefik will log these as if they were logged at `DEBUG` level. Setting `infoToStdout` to `true` will send all non-error info messages to STDOUT and these will appear in logs at `DEBUG` level. These will obviously only appear if you set your traefik log level to `DEBUG` (which may actually be more irritating if you don't want the spew that this creates, so this option is not enabled by default). Note also that this workaround does not appear to be working correctly in traefik v2 and in this case you may not see info messages at all if you enable this.
7777

7878
### Template Interpolation

jwt.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ func New(_ context.Context, next http.Handler, config *Config, name string) (htt
152152
return nil, err
153153
}
154154

155+
for index, pem := range config.RootCAs {
156+
pem, err := pemContent(pem)
157+
if err != nil {
158+
return nil, fmt.Errorf("failed to load root CA: %v", err)
159+
}
160+
config.RootCAs[index] = pem
161+
}
162+
155163
plugin := JWTPlugin{
156164
next: next,
157165
name: name,
@@ -620,6 +628,18 @@ func canonicalizeDomains(domains []string) []string {
620628
return domains
621629
}
622630

631+
// pemContent returns the value if it is alread a PEM or reads the file if it is a filename.
632+
func pemContent(value string) (string, error) {
633+
if value == "" || strings.HasPrefix(value, "-----BEGIN") {
634+
return value, nil
635+
}
636+
content, err := os.ReadFile(value)
637+
if err != nil {
638+
return "", err
639+
}
640+
return string(content), nil
641+
}
642+
623643
// createDefaultClient returns an http.Client with the given root CAs, or a default client if no root CAs are provided.
624644
func createDefaultClient(pems []string, useSystemCertPool bool) *http.Client {
625645
if pems == nil {

jwt_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,30 @@ func TestServeHTTP(tester *testing.T) {
11151115
Method: jwt.SigningMethodES256,
11161116
HeaderName: "Authorization",
11171117
},
1118+
{
1119+
Name: "RootCAs from file",
1120+
Expect: http.StatusOK,
1121+
Config: `
1122+
rootCAs:
1123+
- testing/rootca.pem
1124+
require:
1125+
aud: test`,
1126+
Claims: `{"aud": "test"}`,
1127+
Method: jwt.SigningMethodES256,
1128+
HeaderName: "Authorization",
1129+
},
1130+
{
1131+
Name: "RootCAs from bad file",
1132+
ExpectPluginError: "failed to load root CA: open notexist/rootca.pem: no such file or directory",
1133+
Config: `
1134+
rootCAs:
1135+
- notexist/rootca.pem
1136+
require:
1137+
aud: test`,
1138+
Claims: `{"aud": "test"}`,
1139+
Method: jwt.SigningMethodES256,
1140+
HeaderName: "Authorization",
1141+
},
11181142
{
11191143
Name: "Bad RootCAs",
11201144
Expect: http.StatusOK,

testing/ec-public.pem

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-----BEGIN EC PUBLIC KEY-----
2+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEE7gFCo/g2PQmC3i5kIqVgCCzr2D1
3+
nbCeipqfvK1rkqmKfhb7rlVehfC7ITUAy8NIvQ/AsXClvgHDv55BfOoL6w==
4+
-----END EC PUBLIC KEY-----

testing/rootca.pem

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDJzCCAg+gAwIBAgIUDDYN8pGCpUC6tsqDW4meIXsmN04wDQYJKoZIhvcNAQEL
3+
BQAwIzELMAkGA1UEBhMCVUsxFDASBgNVBAoMC0FnaWxlIFplYnJhMB4XDTI1MDMx
4+
MTE0MTU1MloXDTM1MDMwOTE0MTU1MlowIzELMAkGA1UEBhMCVUsxFDASBgNVBAoM
5+
C0FnaWxlIFplYnJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA70Gs
6+
A3QEKB94Eqyt+V07qDNtykhlyOLSiGIRk1/Slr5B1mTY8Mt88gg8MFldyVukjze+
7+
/5GT/lZ3plMMiA7wnpJ683iWqMVOzQTtYlgcMknnrRJhHuDIGmcdakudXl484emE
8+
9iz+cWgl2cw1rb0rtNC1koQ90MohcTqW+5By0TUaulf80ZcJbGFG8LTqVKVJatET
9+
QedgrYR3tIR6VRtj7pnFZ1w9gZhpPL26mrMg3Wk3GHf/j48jebHVYbeuuSoBXJX8
10+
rGmfCtwzMWqyZvMU9MRP6KpPu20UIOuzau6JyD22RhlLSrX/1eI9Et0IMqEF/iM/
11+
EGpTGDJTeX3bJavzAQIDAQABo1MwUTAdBgNVHQ4EFgQUwR3igK8QvKXQ3JuGlYUc
12+
1jHwBqUwHwYDVR0jBBgwFoAUwR3igK8QvKXQ3JuGlYUc1jHwBqUwDwYDVR0TAQH/
13+
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoEgu6gQTf8Br0Id7Jp6Oht6XSG0o
14+
RtYJ4SwWD0U1acJpWKgtTkBA9cfGMYngFzUe9Xmxt1iBSCJtbQ/SQj5x0vcXsoR0
15+
zWBnihf3XERnJOyLWR7cUCfVYEu0xFCNrc1m5Wzj4IG2NJBTtiIiAdnTbEcBd7hk
16+
f7Vy+al187qn3HQcwdRfMatjFrrM92tHvd79VJsZcgj8Yl3QcgZFIQ2O+PtrXxLR
17+
2auMwVTxdRe0QUT6zvtZGf1niNH5s8DBVeDWqBArlC7M/HuLj6QOIMDEI2aC3yS1
18+
LT12fZ0MWBjfGc90EEJ9z4/CRUWMdtlOaLnXinyrvOH+SSTJD8xfwKqH6g==
19+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)