forked from ggicci/caddy-jwt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
caddyfile.go
129 lines (112 loc) Β· 3.48 KB
/
caddyfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package caddyjwt
import (
"fmt"
"strings"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
"github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth"
)
func init() {
httpcaddyfile.RegisterHandlerDirective("jwtauth", parseCaddyfile)
}
// parseCaddyfile sets up the handler from Caddyfile. Syntax:
//
// jwtauth [<matcher>] {
// sign_key <sign_key>
// ...
// }
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
var ja JWTAuth
for h.Next() {
for h.NextBlock(0) {
opt := h.Val()
switch opt {
case "sign_key":
if !h.AllArgs(&ja.SignKey) {
return nil, h.Errf("invalid sign_key: %q", ja.SignKey)
}
case "sign_alg":
if !h.AllArgs(&ja.SignAlgorithm) {
return nil, h.Errf("invalid sign_alg: %q", ja.SignAlgorithm)
}
case "jwk_url":
ja.JwkUrls = make([]string, 0)
for nesting := h.Nesting(); h.NextBlock(nesting); {
url := h.Val()
ja.JwkUrls = append(ja.JwkUrls, url)
}
if len(ja.JwkUrls) == 0 {
return nil, h.Errf("invalid jwk_url")
}
case "from_query":
ja.FromQuery = h.RemainingArgs()
case "from_header":
ja.FromHeader = h.RemainingArgs()
case "from_cookies":
ja.FromCookies = h.RemainingArgs()
case "audience_whitelist":
ja.AudienceWhitelist = h.RemainingArgs()
case "issuer_whitelist":
ja.IssuerWhitelist = h.RemainingArgs()
case "user_claims":
ja.UserClaims = h.RemainingArgs()
case "meta_claims":
ja.MetaClaims = make(map[string]string)
for _, metaClaim := range h.RemainingArgs() {
claim, placeholder, err := parseMetaClaim(metaClaim)
if err != nil {
return nil, h.Errf("invalid meta_claims: %w", err)
}
if _, ok := ja.MetaClaims[claim]; ok {
return nil, h.Errf("invalid meta_claims: duplicate claim: %s", claim)
}
ja.MetaClaims[claim] = placeholder
}
case "verify_claims":
ja.VerifyClaims = make(map[string]string)
for _, verifyClaim := range h.RemainingArgs() {
claim, value, err := parseMetaClaim(verifyClaim)
if err != nil {
return nil, h.Errf("invalid verify_claims: %w", err)
}
if _, ok := ja.VerifyClaims[claim]; ok {
return nil, h.Errf("invalid verify_claims: duplicate claim: %s", claim)
}
ja.VerifyClaims[claim] = value
}
case "header_first":
return nil, h.Err("option header_first deprecated, the priority now defaults to from_query > from_header > from_cookies")
default:
return nil, h.Errf("unrecognized option: %s", opt)
}
}
}
return caddyauth.Authentication{
ProvidersRaw: caddy.ModuleMap{
"jwt": caddyconfig.JSON(ja, nil),
},
}, nil
}
// parseMetaClaim parses key to get the claim and corresponding placeholder.
// e.g "IsAdmin -> is_admin" as { Claim: "IsAdmin", Placeholder: "is_admin" }.
func parseMetaClaim(key string) (claim, placeholder string, err error) {
parts := strings.Split(key, "->")
if len(parts) == 1 {
claim = strings.TrimSpace(parts[0])
placeholder = strings.TrimSpace(parts[0])
} else if len(parts) == 2 {
claim = strings.TrimSpace(parts[0])
placeholder = strings.TrimSpace(parts[1])
} else {
return "", "", fmt.Errorf("too many delimiters (->) in key %q", key)
}
if claim == "" {
return "", "", fmt.Errorf("empty claim in key %q", key)
}
if placeholder == "" {
return "", "", fmt.Errorf("empty placeholder in key %q", key)
}
return
}