1
- package main
1
+ package config
2
2
3
3
import (
4
4
"errors"
@@ -12,80 +12,78 @@ import (
12
12
)
13
13
14
14
const (
15
- DefaultStatusOnError uint32 = http .StatusForbidden
15
+ DefaultStatusOnError = http .StatusForbidden
16
16
17
- DefaultHttpServiceTimeout uint32 = 1000
17
+ DefaultHttpServiceTimeout = 1000
18
18
19
- DefaultMaxRequestBodyBytes uint32 = 10 * 1024 * 1024
20
-
21
- EndpointModeEnvoy = "envoy"
19
+ DefaultMaxRequestBodyBytes = 10 * 1024 * 1024
22
20
21
+ EndpointModeEnvoy = "envoy"
23
22
EndpointModeForwardAuth = "forward_auth"
24
23
)
25
24
26
25
type ExtAuthConfig struct {
27
- httpService HttpService
28
- failureModeAllow bool
29
- failureModeAllowHeaderAdd bool
30
- statusOnError uint32
26
+ HttpService HttpService
27
+ MatchRules expr.MatchRules
28
+ FailureModeAllow bool
29
+ FailureModeAllowHeaderAdd bool
30
+ StatusOnError uint32
31
31
}
32
32
33
33
type HttpService struct {
34
- endpointMode string
35
- client wrapper.HttpClient
36
- // pathPrefix is only used when endpoint_mode is envoy
37
- pathPrefix string
38
- // requestMethod is only used when endpoint_mode is forward_auth
39
- requestMethod string
40
- // path is only used when endpoint_mode is forward_auth
41
- path string
42
- timeout uint32
43
- authorizationRequest AuthorizationRequest
44
- authorizationResponse AuthorizationResponse
34
+ EndpointMode string
35
+ Client wrapper.HttpClient
36
+ // PathPrefix is only used when endpoint_mode is envoy
37
+ PathPrefix string
38
+ // RequestMethod is only used when endpoint_mode is forward_auth
39
+ RequestMethod string
40
+ // Path is only used when endpoint_mode is forward_auth
41
+ Path string
42
+ Timeout uint32
43
+ AuthorizationRequest AuthorizationRequest
44
+ AuthorizationResponse AuthorizationResponse
45
45
}
46
46
47
47
type AuthorizationRequest struct {
48
- // allowedHeaders In addition to the user’s supplied matchers,
49
- // Authorization are automatically included to the list.
50
- // When the endpoint_mode is set to forward_auth,
51
- // the original request's path is set in the X-Original-Uri header,
52
- // and the original request's HTTP method is set in the X-Original-Method header.
53
- allowedHeaders expr.Matcher
54
- headersToAdd map [string ]string
55
- withRequestBody bool
56
- maxRequestBodyBytes uint32
48
+ AllowedHeaders expr.Matcher
49
+ HeadersToAdd map [string ]string
50
+ WithRequestBody bool
51
+ MaxRequestBodyBytes uint32
57
52
}
58
53
59
54
type AuthorizationResponse struct {
60
- allowedUpstreamHeaders expr.Matcher
61
- allowedClientHeaders expr.Matcher
55
+ AllowedUpstreamHeaders expr.Matcher
56
+ AllowedClientHeaders expr.Matcher
62
57
}
63
58
64
- func parseConfig (json gjson.Result , config * ExtAuthConfig , log wrapper.Log ) error {
59
+ func ParseConfig (json gjson.Result , config * ExtAuthConfig , log wrapper.Log ) error {
65
60
httpServiceConfig := json .Get ("http_service" )
66
61
if ! httpServiceConfig .Exists () {
67
62
return errors .New ("missing http_service in config" )
68
63
}
69
- err := parseHttpServiceConfig (httpServiceConfig , config , log )
70
- if err != nil {
64
+ if err := parseHttpServiceConfig (httpServiceConfig , config , log ); err != nil {
65
+ return err
66
+ }
67
+
68
+ if err := parseMatchRules (json , config , log ); err != nil {
71
69
return err
72
70
}
73
71
74
72
failureModeAllow := json .Get ("failure_mode_allow" )
75
73
if failureModeAllow .Exists () {
76
- config .failureModeAllow = failureModeAllow .Bool ()
74
+ config .FailureModeAllow = failureModeAllow .Bool ()
77
75
}
78
76
79
77
failureModeAllowHeaderAdd := json .Get ("failure_mode_allow_header_add" )
80
78
if failureModeAllowHeaderAdd .Exists () {
81
- config .failureModeAllowHeaderAdd = failureModeAllowHeaderAdd .Bool ()
79
+ config .FailureModeAllowHeaderAdd = failureModeAllowHeaderAdd .Bool ()
82
80
}
83
81
84
82
statusOnError := uint32 (json .Get ("status_on_error" ).Uint ())
85
83
if statusOnError == 0 {
86
84
statusOnError = DefaultStatusOnError
87
85
}
88
- config .statusOnError = statusOnError
86
+ config .StatusOnError = statusOnError
89
87
90
88
return nil
91
89
}
@@ -101,7 +99,7 @@ func parseHttpServiceConfig(json gjson.Result, config *ExtAuthConfig, log wrappe
101
99
if timeout == 0 {
102
100
timeout = DefaultHttpServiceTimeout
103
101
}
104
- httpService .timeout = timeout
102
+ httpService .Timeout = timeout
105
103
106
104
if err := parseAuthorizationRequestConfig (json , & httpService ); err != nil {
107
105
return err
@@ -111,7 +109,7 @@ func parseHttpServiceConfig(json gjson.Result, config *ExtAuthConfig, log wrappe
111
109
return err
112
110
}
113
111
114
- config .httpService = httpService
112
+ config .HttpService = httpService
115
113
116
114
return nil
117
115
}
@@ -123,7 +121,7 @@ func parseEndpointConfig(json gjson.Result, httpService *HttpService, log wrappe
123
121
} else if endpointMode != EndpointModeEnvoy && endpointMode != EndpointModeForwardAuth {
124
122
return errors .New (fmt .Sprintf ("endpoint_mode %s is not supported" , endpointMode ))
125
123
}
126
- httpService .endpointMode = endpointMode
124
+ httpService .EndpointMode = endpointMode
127
125
128
126
endpointConfig := json .Get ("endpoint" )
129
127
if ! endpointConfig .Exists () {
@@ -140,7 +138,7 @@ func parseEndpointConfig(json gjson.Result, httpService *HttpService, log wrappe
140
138
}
141
139
serviceHost := endpointConfig .Get ("service_host" ).String ()
142
140
143
- httpService .client = wrapper .NewClusterClient (wrapper.FQDNCluster {
141
+ httpService .Client = wrapper .NewClusterClient (wrapper.FQDNCluster {
144
142
FQDN : serviceName ,
145
143
Port : servicePort ,
146
144
Host : serviceHost ,
@@ -152,24 +150,24 @@ func parseEndpointConfig(json gjson.Result, httpService *HttpService, log wrappe
152
150
if ! pathPrefixConfig .Exists () {
153
151
return errors .New ("when endpoint_mode is envoy, endpoint path_prefix must not be empty" )
154
152
}
155
- httpService .pathPrefix = pathPrefixConfig .String ()
153
+ httpService .PathPrefix = pathPrefixConfig .String ()
156
154
157
155
if endpointConfig .Get ("request_method" ).Exists () || endpointConfig .Get ("path" ).Exists () {
158
156
log .Warn ("when endpoint_mode is envoy, endpoint request_method and path will be ignored" )
159
157
}
160
158
case EndpointModeForwardAuth :
161
159
requestMethodConfig := endpointConfig .Get ("request_method" )
162
160
if ! requestMethodConfig .Exists () {
163
- httpService .requestMethod = http .MethodGet
161
+ httpService .RequestMethod = http .MethodGet
164
162
} else {
165
- httpService .requestMethod = strings .ToUpper (requestMethodConfig .String ())
163
+ httpService .RequestMethod = strings .ToUpper (requestMethodConfig .String ())
166
164
}
167
165
168
166
pathConfig := endpointConfig .Get ("path" )
169
167
if ! pathConfig .Exists () {
170
168
return errors .New ("when endpoint_mode is forward_auth, endpoint path must not be empty" )
171
169
}
172
- httpService .path = pathConfig .String ()
170
+ httpService .Path = pathConfig .String ()
173
171
174
172
if endpointConfig .Get ("path_prefix" ).Exists () {
175
173
log .Warn ("when endpoint_mode is forward_auth, endpoint path_prefix will be ignored" )
@@ -189,35 +187,28 @@ func parseAuthorizationRequestConfig(json gjson.Result, httpService *HttpService
189
187
if err != nil {
190
188
return err
191
189
}
192
- authorizationRequest .allowedHeaders = result
190
+ authorizationRequest .AllowedHeaders = result
193
191
}
194
192
195
- headersToAdd := map [string ]string {}
196
- headersToAddConfig := authorizationRequestConfig .Get ("headers_to_add" )
197
- if headersToAddConfig .Exists () {
198
- for key , value := range headersToAddConfig .Map () {
199
- headersToAdd [key ] = value .Str
200
- }
201
- }
202
- authorizationRequest .headersToAdd = headersToAdd
193
+ authorizationRequest .HeadersToAdd = convertToStringMap (authorizationRequestConfig .Get ("headers_to_add" ))
203
194
204
195
withRequestBody := authorizationRequestConfig .Get ("with_request_body" )
205
196
if withRequestBody .Exists () {
206
197
// withRequestBody is true and the request method is GET, OPTIONS or HEAD
207
198
if withRequestBody .Bool () &&
208
- (httpService .requestMethod == http .MethodGet || httpService .requestMethod == http .MethodOptions || httpService .requestMethod == http .MethodHead ) {
209
- return errors .New (fmt .Sprintf ("requestMethod %s does not support with_request_body set to true" , httpService .requestMethod ))
199
+ (httpService .RequestMethod == http .MethodGet || httpService .RequestMethod == http .MethodOptions || httpService .RequestMethod == http .MethodHead ) {
200
+ return errors .New (fmt .Sprintf ("requestMethod %s does not support with_request_body set to true" , httpService .RequestMethod ))
210
201
}
211
- authorizationRequest .withRequestBody = withRequestBody .Bool ()
202
+ authorizationRequest .WithRequestBody = withRequestBody .Bool ()
212
203
}
213
204
214
205
maxRequestBodyBytes := uint32 (authorizationRequestConfig .Get ("max_request_body_bytes" ).Uint ())
215
206
if maxRequestBodyBytes == 0 {
216
207
maxRequestBodyBytes = DefaultMaxRequestBodyBytes
217
208
}
218
- authorizationRequest .maxRequestBodyBytes = maxRequestBodyBytes
209
+ authorizationRequest .MaxRequestBodyBytes = maxRequestBodyBytes
219
210
220
- httpService .authorizationRequest = authorizationRequest
211
+ httpService .AuthorizationRequest = authorizationRequest
221
212
}
222
213
return nil
223
214
}
@@ -233,7 +224,7 @@ func parseAuthorizationResponseConfig(json gjson.Result, httpService *HttpServic
233
224
if err != nil {
234
225
return err
235
226
}
236
- authorizationResponse .allowedUpstreamHeaders = result
227
+ authorizationResponse .AllowedUpstreamHeaders = result
237
228
}
238
229
239
230
allowedClientHeaders := authorizationResponseConfig .Get ("allowed_client_headers" )
@@ -242,10 +233,62 @@ func parseAuthorizationResponseConfig(json gjson.Result, httpService *HttpServic
242
233
if err != nil {
243
234
return err
244
235
}
245
- authorizationResponse .allowedClientHeaders = result
236
+ authorizationResponse .AllowedClientHeaders = result
237
+ }
238
+
239
+ httpService .AuthorizationResponse = authorizationResponse
240
+ }
241
+ return nil
242
+ }
243
+
244
+ func parseMatchRules (json gjson.Result , config * ExtAuthConfig , log wrapper.Log ) error {
245
+ matchListConfig := json .Get ("match_list" )
246
+ if ! matchListConfig .Exists () {
247
+ config .MatchRules = expr .MatchRulesDefaults ()
248
+ return nil
249
+ }
250
+
251
+ matchType := json .Get ("match_type" )
252
+ if ! matchType .Exists () {
253
+ return errors .New ("missing match_type in config" )
254
+ }
255
+ if matchType .Str != expr .ModeWhitelist && matchType .Str != expr .ModeBlacklist {
256
+ return errors .New ("invalid match_type in config, must be 'whitelist' or 'blacklist'" )
257
+ }
258
+
259
+ ruleList := make ([]expr.Rule , 0 )
260
+ var err error
261
+
262
+ matchListConfig .ForEach (func (key , value gjson.Result ) bool {
263
+ pathMatcher , err := expr .BuildStringMatcher (
264
+ value .Get ("match_rule_type" ).Str ,
265
+ value .Get ("match_rule_path" ).Str , false )
266
+ if err != nil {
267
+ return false // stop iterating
246
268
}
269
+ ruleList = append (ruleList , expr.Rule {
270
+ Domain : value .Get ("match_rule_domain" ).Str ,
271
+ Path : pathMatcher ,
272
+ })
273
+ return true // keep iterating
274
+ })
247
275
248
- httpService .authorizationResponse = authorizationResponse
276
+ if err != nil {
277
+ return fmt .Errorf ("failed to build string matcher for rule %v: %w" , matchListConfig , err )
278
+ }
279
+
280
+ config .MatchRules = expr.MatchRules {
281
+ Mode : matchType .Str ,
282
+ RuleList : ruleList ,
249
283
}
250
284
return nil
251
285
}
286
+
287
+ func convertToStringMap (result gjson.Result ) map [string ]string {
288
+ m := make (map [string ]string )
289
+ result .ForEach (func (key , value gjson.Result ) bool {
290
+ m [key .String ()] = value .String ()
291
+ return true // keep iterating
292
+ })
293
+ return m
294
+ }
0 commit comments