Commit 65ab4547 by Geoff Simmons

Auth config uses the same conditions array as for ACLs.

Closes #22
parent 6af60a42
...@@ -79,15 +79,28 @@ spec: ...@@ -79,15 +79,28 @@ spec:
type: string type: string
utf8: utf8:
type: boolean type: boolean
condition: conditions:
type: object type: array
properties: minItems: 1
url-match: items:
type: string type: object
minLength: 1 required:
host-match: - comparand
type: string - value
minLength: 1 properties:
comparand:
type: string
pattern: "^req\\.(url|http\\.[a-zA-Z0-9!#$%&'*+.^_`|~-]+)$"
compare:
enum:
- equal
- not-equal
- match
- not-match
type: string
value:
type: string
minLength: 1
acl: acl:
type: array type: array
minItems: 1 minItems: 1
......
...@@ -191,26 +191,56 @@ These fields in the elements of ``auth`` are optional: ...@@ -191,26 +191,56 @@ These fields in the elements of ``auth`` are optional:
encoding is used for the username/password (see encoding is used for the username/password (see
[RFC 7617 2.1](https://tools.ietf.org/html/rfc7617#section-2.1)). [RFC 7617 2.1](https://tools.ietf.org/html/rfc7617#section-2.1)).
By default, ``charset`` is ``false``. By default, ``charset`` is ``false``.
* ``condition``: conditions under which the authentication protocol is * ``conditions``: conditions under which the authentication protocol is
to be executed. to be executed.
If the ``condition`` object is present, it may have either or both of If the ``conditions`` array is present, then it MUST have at least one
these fields: element, and each element must specify at least these two fields:
* ``url-match`` (regular expression): pattern to match against the * ``comparand`` (string): either ``req.url`` or ``req.http.$HEADER``,
URL path of the request where ``$HEADER`` is the name of a client request header.
* ``host-match`` (regular expression): pattern to match against the
``Host`` request header * ``value`` (string): the value against which the ``comparand``
is compared
If either or both of these two fields are present, then the ``conditions`` may also have this optional field:
authentication protocol is executed for matching requests. If the
``condition`` is left out, then the authentication is required for * ``compare``: one of the following (default ``equal``):
every client request. The patterns in ``url-match`` and
``host-match`` are implemented as * ``equal`` for string equality
* ``not-equal`` for string inequality
* ``match`` for regex match
* ``not-match`` for regex non-match
If ``compare`` is ``equal`` or ``not-equal``, then ``value`` is
interpreted as a fixed string, and ``comparand`` is tested for
(in)equality with ``value``. Otherwise, ``value`` is interpreted as a
regular expression, and the ``comparand`` is tested for
(non-)match. Regexen are implemented as
[VCL regular expressions](https://varnish-cache.org/docs/6.1/reference/vcl.html#regular-expressions), [VCL regular expressions](https://varnish-cache.org/docs/6.1/reference/vcl.html#regular-expressions),
and hence have the syntax and semantics of and hence have the syntax and semantics of
[PCRE](https://www.pcre.org/original/doc/html/). [PCRE](https://www.pcre.org/original/doc/html/).
The authentication protocol is executed only if all of the
``conditions`` succeed; in other words, the ``conditions`` are the
boolean AND of all of the match terms.
For example, these ``conditions`` specify that authentication is
executed when the URL begins with "/tea", and the Host header is
exactly "cafe.example.com":
```
conditions:
- comparand: req.url
compare: match
value: ^/tea(/|$)
- comparand: req.http.Host
value: cafe.example.com
```
Validation for ``VarnishConfig`` reports errors at apply time if: Validation for ``VarnishConfig`` reports errors at apply time if:
* the ``auth`` array is empty * the ``auth`` array is empty
...@@ -218,10 +248,10 @@ Validation for ``VarnishConfig`` reports errors at apply time if: ...@@ -218,10 +248,10 @@ Validation for ``VarnishConfig`` reports errors at apply time if:
* any of the string fields are empty * any of the string fields are empty
* ``type`` has an illegal value (neither of ``basic`` or ``proxy``) * ``type`` has an illegal value (neither of ``basic`` or ``proxy``)
Other errors, in particular illegal regex syntax for ``url-match`` or Other errors, in particular illegal regex syntax for ``conditions``,
``host-match``, are not reported until VCL load time. Check the are not reported until VCL load time. Check the controller log and
controller log and Events generated for the Varnish Service for error Events generated for the Varnish Service for error messages from the
messages from the VCL compiler. VCL compiler.
Examples: Examples:
``` ```
...@@ -237,9 +267,13 @@ spec: ...@@ -237,9 +267,13 @@ spec:
secretName: coffee-creds secretName: coffee-creds
type: basic type: basic
utf8: true utf8: true
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/coffee($|/) value: cafe.example.com
compare: equal
- comparand: req.url
value: ^/coffee($|/)
compare: match
# For the tea Service, require authentication for the realm "tea" # For the tea Service, require authentication for the realm "tea"
# when the Host is "cafe.example.com" and the URL path begins with # when the Host is "cafe.example.com" and the URL path begins with
...@@ -248,9 +282,13 @@ spec: ...@@ -248,9 +282,13 @@ spec:
# left out. # left out.
- realm: tea - realm: tea
secretName: tea-creds secretName: tea-creds
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/tea($|/) value: cafe.example.com
compare: equal
- comparand: req.url
value: ^/tea($|/)
compare: match
``` ```
``` ```
spec: spec:
...@@ -288,8 +326,10 @@ Optional fields for ``acl`` are: ...@@ -288,8 +326,10 @@ Optional fields for ``acl`` are:
is matched, as detailed below; default ``client.ip`` is matched, as detailed below; default ``client.ip``
* ``conditions``: array of conditions under which the ACL match is * ``conditions``: array of conditions under which the ACL match is
executed, as detailed below. By default, ``conditions`` is empty, executed. The ``conditions`` field has the same syntax and semantics
in which case the match is executed for every client request. as specified above for ``spec.auth`` (Basic and Proxy
Authentication). By default, ``conditions`` is empty, in which case
the match is executed for every client request.
* ``result-header``: specifies a client request header and values to * ``result-header``: specifies a client request header and values to
set for the header when the failure status is or is not invoked for set for the header when the failure status is or is not invoked for
...@@ -414,52 +454,10 @@ X-Forwarded-For: 192.0.2.47, 203.0.113.11 ...@@ -414,52 +454,10 @@ X-Forwarded-For: 192.0.2.47, 203.0.113.11
``xff-2ndlast`` specifies a match against 203.0.113.11. ``xff-2ndlast`` specifies a match against 203.0.113.11.
If ``conditions`` are specified for an ACL, they define restrictions If ``conditions`` are specified for an ACL, they define restrictions
for executing the match. Each element of ``conditions`` must specify for executing the match; the ACL match is executed only if all of the
these two required fields: ``conditions`` succeed. The ``conditions`` field for ACLs has the same
syntax and semantics as specified above for Basic and Proxy
* ``comparand`` (string): either ``req.url`` or ``req.http.$HEADER``, Authentication.
where ``$HEADER`` is the name of a client request header.
* ``value`` (string): the value against which the ``comparand``
is compared
``conditions`` may also have this optional field:
* ``compare``: one of the following (default ``equal``):
* ``equal`` for string equality
* ``not-equal`` for string inequality
* ``match`` for regex match
* ``not-match`` for regex non-match
If ``compare`` is ``equal`` or ``not-equal``, then ``value`` is
interpreted as a fixed string, and ``comparand`` is tested for
(in)equality with ``value``. Otherwise, ``value`` is interpreted as a
regular expression, and the ``comparand`` is tested for
(non-)match. Regexen are implemented as
[VCL regular expressions](https://varnish-cache.org/docs/6.1/reference/vcl.html#regular-expressions),
and hence have the syntax and semantics of
[PCRE](https://www.pcre.org/original/doc/html/).
The ACL match is executed only if all of the ``conditions`` succeed;
in other words, the ``conditions`` are the boolean AND of all of the
match terms.
For example, these ``conditions`` specify that the match is executed
when the URL begins with "/tea", and the Host header is exactly
"cafe.example.com":
```
conditions:
- comparand: req.url
compare: match
value: ^/tea(/|$)
- comparand: req.http.Host
value: cafe.example.com
```
The ``result-header`` field specifies a client request header that is The ``result-header`` field specifies a client request header that is
set with a value for the "fail" or "success" results of the ACL set with a value for the "fail" or "success" results of the ACL
......
...@@ -69,15 +69,22 @@ from the ``coffee-creds`` Secret: ...@@ -69,15 +69,22 @@ from the ``coffee-creds`` Secret:
secretName: coffee-creds secretName: coffee-creds
type: basic type: basic
utf8: true utf8: true
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/coffee($|/) value: cafe.example.com
``` compare: equal
- comparand: req.url
``type: basic`` specifies Basic Authentication, and the ``host-match`` value: ^/coffee($|/)
and ``url-match`` fields require authentication in the "coffee" realm compare: match
when the Host is exactly equal to "cafe.example.com", and the URL path ```
begins with "/coffee".
``type: basic`` specifies Basic Authentication, and the ``conditions``
array requires authentication when a request is routed to the
coffee-svc Service. The first element of ``comparand`` specifies that
the Host header is exactly equal to "cafe.example.com", and the second
specifies that the URL path begins with "/coffee". The Basic
Authentication protocol configured here is only executed when all of
the ``conditions`` are met.
The ``utf8: true`` setting means that the field ``charset="UTF-8"`` The ``utf8: true`` setting means that the field ``charset="UTF-8"``
field is appended to the ``WWW-Authenticate`` response header when field is appended to the ``WWW-Authenticate`` response header when
...@@ -93,9 +100,13 @@ from the ``tea-creds`` Secret when the URL path begins with "/tea": ...@@ -93,9 +100,13 @@ from the ``tea-creds`` Secret when the URL path begins with "/tea":
``` ```
- realm: tea - realm: tea
secretName: tea-creds secretName: tea-creds
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/tea($|/) value: cafe.example.com
compare: equal
- comparand: req.url
value: ^/tea($|/)
compare: match
``` ```
Not that ``type: basic`` was left out here, since ``basic`` is the Not that ``type: basic`` was left out here, since ``basic`` is the
...@@ -175,9 +186,9 @@ unconditionally to all requests: ...@@ -175,9 +186,9 @@ unconditionally to all requests:
``` ```
As with Basic Authentication, it is also possible to use the As with Basic Authentication, it is also possible to use the
``condition.host-match`` and ``condition.url-match`` fields to ``conditions`` array to restrict the requests for which the
restrict the requests for which the authentication is required (but authentication is required (but Proxy Authentication typically applies
Proxy Authentication typically applies to all requests). to all requests).
To verify with curl, we use the ``-x`` (or ``--proxy``) argument to To verify with curl, we use the ``-x`` (or ``--proxy``) argument to
specify ``$ADDR:$PORT`` as the proxy, and send the request with an specify ``$ADDR:$PORT`` as the proxy, and send the request with an
......
...@@ -22,9 +22,13 @@ spec: ...@@ -22,9 +22,13 @@ spec:
secretName: coffee-creds secretName: coffee-creds
type: basic type: basic
utf8: true utf8: true
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/coffee($|/) value: cafe.example.com
compare: equal
- comparand: req.url
value: ^/coffee($|/)
compare: match
# For the tea Service, require authentication for the realm "tea" # For the tea Service, require authentication for the realm "tea"
# when the Host is "cafe.example.com" and the URL path begins with # when the Host is "cafe.example.com" and the URL path begins with
...@@ -33,6 +37,10 @@ spec: ...@@ -33,6 +37,10 @@ spec:
# left out. # left out.
- realm: tea - realm: tea
secretName: tea-creds secretName: tea-creds
condition: conditions:
host-match: ^cafe\.example\.com$ - comparand: req.http.Host
url-match: ^/tea($|/) value: cafe.example.com
compare: equal
- comparand: req.url
value: ^/tea($|/)
compare: match
...@@ -79,11 +79,11 @@ type ProbeSpec struct { ...@@ -79,11 +79,11 @@ type ProbeSpec struct {
// AuthSpec specifies authentication (basic or proxy). // AuthSpec specifies authentication (basic or proxy).
type AuthSpec struct { type AuthSpec struct {
Realm string `json:"realm"` Realm string `json:"realm"`
SecretName string `json:"secretName"` SecretName string `json:"secretName"`
Type AuthType `json:"type,omitempty"` Type AuthType `json:"type,omitempty"`
Condition *AuthCondition `json:"condition,omitempty"` UTF8 bool `json:"utf8,omitempty"`
UTF8 bool `json:"utf8,omitempty"` Conditions []Condition `json:"conditions,omitempty"`
} }
// AuthType classifies the protocol for an AuthSpec. // AuthType classifies the protocol for an AuthSpec.
...@@ -96,14 +96,6 @@ const ( ...@@ -96,14 +96,6 @@ const (
Proxy = "proxy" Proxy = "proxy"
) )
// AuthCondition specifies a condition under which an authentication
// protocol must be executed -- the URL path or the Host must match a
// pattern (or both).
type AuthCondition struct {
URLRegex string `json:"url-match,omitempty"`
HostRegex string `json:"host-match,omitempty"`
}
// ACLSpec specifies whitelisting or blacklisting IP addresses against // ACLSpec specifies whitelisting or blacklisting IP addresses against
// an access control list. // an access control list.
type ACLSpec struct { type ACLSpec struct {
......
...@@ -94,28 +94,12 @@ func (in *ACLSpec) DeepCopy() *ACLSpec { ...@@ -94,28 +94,12 @@ func (in *ACLSpec) DeepCopy() *ACLSpec {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AuthCondition) DeepCopyInto(out *AuthCondition) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthCondition.
func (in *AuthCondition) DeepCopy() *AuthCondition {
if in == nil {
return nil
}
out := new(AuthCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AuthSpec) DeepCopyInto(out *AuthSpec) { func (in *AuthSpec) DeepCopyInto(out *AuthSpec) {
*out = *in *out = *in
if in.Condition != nil { if in.Conditions != nil {
in, out := &in.Condition, &out.Condition in, out := &in.Conditions, &out.Conditions
*out = new(AuthCondition) *out = make([]Condition, len(*in))
**out = **in copy(*out, *in)
} }
return return
} }
......
...@@ -326,6 +326,33 @@ func (worker *NamespaceWorker) configSharding(spec *vcl.Spec, ...@@ -326,6 +326,33 @@ func (worker *NamespaceWorker) configSharding(spec *vcl.Spec,
return nil return nil
} }
func configConditions(vclConds []vcl.MatchTerm,
vcfgConds []vcr_v1alpha1.Condition) {
if len(vclConds) != len(vcfgConds) {
panic("configConditions: unequal slice lengths")
}
for i, cond := range vcfgConds {
vclMatch := vcl.MatchTerm{
Comparand: cond.Comparand,
Value: cond.Value,
}
switch cond.Compare {
case vcr_v1alpha1.Equal:
vclMatch.Compare = vcl.Equal
case vcr_v1alpha1.NotEqual:
vclMatch.Compare = vcl.NotEqual
case vcr_v1alpha1.Match:
vclMatch.Compare = vcl.Match
case vcr_v1alpha1.NotMatch:
vclMatch.Compare = vcl.NotMatch
default:
vclMatch.Compare = vcl.Equal
}
vclConds[i] = vclMatch
}
}
func (worker *NamespaceWorker) configAuth(spec *vcl.Spec, func (worker *NamespaceWorker) configAuth(spec *vcl.Spec,
vcfg *vcr_v1alpha1.VarnishConfig) error { vcfg *vcr_v1alpha1.VarnishConfig) error {
...@@ -357,6 +384,7 @@ func (worker *NamespaceWorker) configAuth(spec *vcl.Spec, ...@@ -357,6 +384,7 @@ func (worker *NamespaceWorker) configAuth(spec *vcl.Spec,
vclAuth := vcl.Auth{ vclAuth := vcl.Auth{
Realm: auth.Realm, Realm: auth.Realm,
Credentials: make([]string, 0, len(secret.Data)), Credentials: make([]string, 0, len(secret.Data)),
Conditions: make([]vcl.MatchTerm, len(auth.Conditions)),
UTF8: auth.UTF8, UTF8: auth.UTF8,
} }
if auth.Type == "" || auth.Type == vcr_v1alpha1.Basic { if auth.Type == "" || auth.Type == vcr_v1alpha1.Basic {
...@@ -372,10 +400,7 @@ func (worker *NamespaceWorker) configAuth(spec *vcl.Spec, ...@@ -372,10 +400,7 @@ func (worker *NamespaceWorker) configAuth(spec *vcl.Spec,
vcfg.Name, cred, vclAuth.Realm) vcfg.Name, cred, vclAuth.Realm)
vclAuth.Credentials = append(vclAuth.Credentials, cred) vclAuth.Credentials = append(vclAuth.Credentials, cred)
} }
if auth.Condition != nil { configConditions(vclAuth.Conditions, auth.Conditions)
vclAuth.Condition.URLRegex = auth.Condition.URLRegex
vclAuth.Condition.HostRegex = auth.Condition.HostRegex
}
worker.log.Debugf("VarnishConfig %s/%s add VCL auth config: "+ worker.log.Debugf("VarnishConfig %s/%s add VCL auth config: "+
"%+v", vcfg.Namespace, vcfg.Name, vclAuth) "%+v", vcfg.Namespace, vcfg.Name, vclAuth)
spec.Auths = append(spec.Auths, vclAuth) spec.Auths = append(spec.Auths, vclAuth)
...@@ -426,23 +451,7 @@ func (worker *NamespaceWorker) configACL(spec *vcl.Spec, ...@@ -426,23 +451,7 @@ func (worker *NamespaceWorker) configACL(spec *vcl.Spec,
} }
vclACL.Addresses[j] = vclAddr vclACL.Addresses[j] = vclAddr
} }
for j, cond := range acl.Conditions { configConditions(vclACL.Conditions, acl.Conditions)
vclMatch := vcl.MatchTerm{
Comparand: cond.Comparand,
Value: cond.Value,
}
switch cond.Compare {
case vcr_v1alpha1.Equal:
vclMatch.Compare = vcl.Equal
case vcr_v1alpha1.NotEqual:
vclMatch.Compare = vcl.NotEqual
case vcr_v1alpha1.Match:
vclMatch.Compare = vcl.Match
case vcr_v1alpha1.NotMatch:
vclMatch.Compare = vcl.NotMatch
}
vclACL.Conditions[j] = vclMatch
}
if acl.ResultHdr != nil { if acl.ResultHdr != nil {
worker.log.Debugf("ACL %s: ResultHdr=%+v", acl.Name, worker.log.Debugf("ACL %s: ResultHdr=%+v", acl.Name,
*acl.ResultHdr) *acl.ResultHdr)
......
...@@ -14,11 +14,8 @@ sub vcl_init { ...@@ -14,11 +14,8 @@ sub vcl_init {
sub vcl_recv { sub vcl_recv {
{{- range .Auths}} {{- range .Auths}}
if ( if (
{{- if ne .Condition.HostRegex ""}} {{- range $cond := .Conditions}}
req.http.Host ~ "{{.Condition.HostRegex}}" && {{$cond.Comparand}} {{cmpRelation .Compare}} "{{.Value}}" &&
{{- end}}
{{- if ne .Condition.URLRegex ""}}
req.url ~ "{{.Condition.URLRegex}}" &&
{{- end}} {{- end}}
{{- if eq .Status 401}} {{- if eq .Status 401}}
!{{credsMatcher .Realm}}.match(req.http.Authorization) !{{credsMatcher .Realm}}.match(req.http.Authorization)
......
...@@ -242,16 +242,6 @@ func (shard ShardCluster) hash(hash hash.Hash) { ...@@ -242,16 +242,6 @@ func (shard ShardCluster) hash(hash hash.Hash) {
hash.Write([]byte(shard.MaxSecondaryTTL)) hash.Write([]byte(shard.MaxSecondaryTTL))
} }
// Condition specifies conditions under which an authentication
// protocols must be executed -- the URL path or the Host must match
// patterns, the request must be received from a TLS offloader, or any
// combination of the three.
type Condition struct {
URLRegex string
HostRegex string
TLS bool
}
// AuthStatus is the response code to be sent for authentication // AuthStatus is the response code to be sent for authentication
// failures, and serves to distinguish the protocols. // failures, and serves to distinguish the protocols.
type AuthStatus uint16 type AuthStatus uint16
...@@ -266,10 +256,10 @@ const ( ...@@ -266,10 +256,10 @@ const (
// Auth specifies Basic or Proxy Authentication, derived from an // Auth specifies Basic or Proxy Authentication, derived from an
// AuthSpec in a VarnishConfig resource. // AuthSpec in a VarnishConfig resource.
type Auth struct { type Auth struct {
Realm string Conditions []MatchTerm
Credentials []string Credentials []string
Realm string
Status AuthStatus Status AuthStatus
Condition Condition
UTF8 bool UTF8 bool
} }
...@@ -281,10 +271,8 @@ func (auth Auth) hash(hash hash.Hash) { ...@@ -281,10 +271,8 @@ func (auth Auth) hash(hash hash.Hash) {
statusBytes := make([]byte, 2) statusBytes := make([]byte, 2)
binary.BigEndian.PutUint16(statusBytes, uint16(auth.Status)) binary.BigEndian.PutUint16(statusBytes, uint16(auth.Status))
hash.Write(statusBytes) hash.Write(statusBytes)
hash.Write([]byte(auth.Condition.URLRegex)) for _, cond := range auth.Conditions {
hash.Write([]byte(auth.Condition.HostRegex)) cond.hash(hash)
if auth.Condition.TLS {
hash.Write([]byte("TLS"))
} }
if auth.UTF8 { if auth.UTF8 {
hash.Write([]byte("UTF8")) hash.Write([]byte("UTF8"))
......
...@@ -42,7 +42,7 @@ sub vcl_recv { ...@@ -42,7 +42,7 @@ sub vcl_recv {
return(synth(60000 + 407)); return(synth(60000 + 407));
} }
if ( if (
req.http.Host ~ "^baz\.com$" && req.http.Host == "baz.com" &&
!vk8s_baz_auth.match(req.http.Authorization) !vk8s_baz_auth.match(req.http.Authorization)
) { ) {
set req.http.VK8S-Authenticate = set req.http.VK8S-Authenticate =
...@@ -58,7 +58,7 @@ sub vcl_recv { ...@@ -58,7 +58,7 @@ sub vcl_recv {
return(synth(60000 + 407)); return(synth(60000 + 407));
} }
if ( if (
req.http.Host ~ "^url\.regex\.org$" && req.http.Host == "url.regex.org" &&
req.url ~ "^/secret/path" && req.url ~ "^/secret/path" &&
!vk8s_urlhost_auth.match(req.http.Authorization) !vk8s_urlhost_auth.match(req.http.Authorization)
) { ) {
......
...@@ -244,9 +244,11 @@ var auths = Spec{ ...@@ -244,9 +244,11 @@ var auths = Spec{
"dXNlcjpwYXNzd29yZDE=", "dXNlcjpwYXNzd29yZDE=",
"bmFtZTpzZWNyZXQ=", "bmFtZTpzZWNyZXQ=",
}, },
Condition: Condition{ Conditions: []MatchTerm{{
HostRegex: `^baz\.com$`, Comparand: "req.http.Host",
}, Value: `baz.com`,
Compare: Equal,
}},
UTF8: true, UTF8: true,
}, },
{ {
...@@ -256,9 +258,11 @@ var auths = Spec{ ...@@ -256,9 +258,11 @@ var auths = Spec{
"YmVudXR6ZXI6Z2VoZWlt", "YmVudXR6ZXI6Z2VoZWlt",
"QWxiZXJ0IEFkZGluOm9wZW4gc2V6IG1l", "QWxiZXJ0IEFkZGluOm9wZW4gc2V6IG1l",
}, },
Condition: Condition{ Conditions: []MatchTerm{{
URLRegex: "^/baz/quux", Comparand: "req.url",
}, Value: "^/baz/quux",
Compare: Match,
}},
UTF8: true, UTF8: true,
}, },
{ {
...@@ -268,9 +272,17 @@ var auths = Spec{ ...@@ -268,9 +272,17 @@ var auths = Spec{
"dXJsOmhvc3Q=", "dXJsOmhvc3Q=",
"YWRtaW46c3VwZXJwb3dlcnM=", "YWRtaW46c3VwZXJwb3dlcnM=",
}, },
Condition: Condition{ Conditions: []MatchTerm{
HostRegex: `^url\.regex\.org$`, {
URLRegex: "^/secret/path", Comparand: "req.http.Host",
Value: "url.regex.org",
Compare: Equal,
},
{
Comparand: "req.url",
Value: "^/secret/path",
Compare: Match,
},
}, },
}, },
}, },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment