From c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 Mon Sep 17 00:00:00 2001
From: Daniel Baumann
+Starting from version 2.1, H2O comes with a DSL-like mruby library which makes it easy to write access control list (ACL).
+
+Below example uses this Access Control feature to write various access control.
+
+In the example, the handler you get by calling
+An ACL handler is built by calling ACL methods, which can be used like directives.
+ACL methods can only be used in
+Each ACL method adds a filter to the handler, which checks whether the request matches the provided condition or not.
+Every ACL method can be accompanied by a condition block, which should return boolean value.
+
+The filter defined by the method that first matched the accompanying condition gets applied (e.g. response
+In a condition block, you can use helpful methods which return particular properties of the request as string values.
+Matching methods can only be used in a condition block of the ACL methods.
+
+Several restrictions are introduced to avoid misconfiguration when using Example
+
+acl
method will do the following:
+
+
+
+403 Forbidden
response
+ malicious_ip
variable, this handler immediately returns 503 Service Unavailable
response
+ /moved/i
, this handler immediately redirects the client to "https://example.com"
with 301
status code
+ /admin
, apply Basic Authentication to the request (for details of Basic Authentication, see here).
+ ACL Methods
+
+acl
block.
+403 Forbidden
, redirect to somewhere).
+If a condition block is omitted, all requests matches.
+If none of the conditions matches the request, the handler returns 399
and the request will be delegated to the next handler.
+
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "deny",
+ desc => q{ Adds a filter which returns allow { ..condition.. }
403 Forbidden
if the request matches the provided condition. },
+)->(sub {
+?>
+
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "redirect",
+ params => [
+ { label => 'location', desc => 'Location to which the client will be redirected. Required.' },
+ { label => 'status', desc => 'Status code of the response. Default value: 302' },
+ ],
+ desc => q{ Adds a filter which redirects the client if the request matches the provided condition. },
+)->(sub {
+?>
+deny { ..condition.. }
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "respond",
+ params => [
+ { label => 'status', desc => 'Status code of the response. Required.' },
+ { label => 'header', desc => 'Header key-value pairs of the response. Default value: {}' },
+ { label => 'body', desc => 'Body array of the response. Default value: []' },
+ ],
+ desc => q{ Adds a filter which returns arbitrary response if the request matches the provided condition. },
+)->(sub {
+?>
+redirect(location, status) { ..condition.. }
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "use",
+ params => [
+ { label => 'proc', desc => 'Callable object that should be applied' },
+ ],
+ desc => q{ Adds a filter which applies the provided handler (callable object) if the request matches the provided condition. },
+)->(sub {
+?>
+respond(status, header, body) { ..condition.. }
+? })
+
+use(proc) { ..condition.. }
Matching Methods
+
+
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "path",
+ desc => q{ Returns the requested path string of the request. },
+)->(sub {
+?>
+addr(forwarded)
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "method",
+ desc => q{ Returns the HTTP method of the request. },
+)->(sub {
+?>
+path()
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "header",
+ params => [
+ { label => 'name', desc => 'Case-insensitive header name. Required.' },
+ ],
+ desc => q{ Returns the header value of the request associated with the provided name. },
+)->(sub {
+?>
+method()
+? })
+
+
+$ctx->{mruby_method}->(
+ name => "user_agent",
+ desc => q{ Shortcut for header("user-agent"). },
+)->(sub {
+?>
+header(name)
+? })
+
+user_agent()
Caution
+
+acl
method.
+
+
+If a configuration violates these restrictions, the server will detect it and refuse to launch with error message.
+acl
method can be called only once in each handler configurationacl
method is used, the handler returned by the configuration directive must be the one returned by the acl
method
+For example, both of the following examples violate the restrictions above, so the server will refuse to start up. +
+ += $ctx->{example}->('Misconfiguration Example 1', <<'EOT'); +paths: + "/": + mruby.handler: | + acl { # this block will be ignored! + allow { addr == "127.0.0.1" } + } + acl { + deny + } + file.dir: /path/to/doc_root +EOT +?> + += $ctx->{example}->('Misconfiguration Example 2', <<'EOT'); +paths: + "/": + mruby.handler: | + acl { # this block will be ignored! + allow { addr == "127.0.0.1" } + deny + } + proc {|env| [399, {}, []} + file.dir: /path/to/doc_root +EOT +?> + ++You can correct these like the following: +
+ += $ctx->{example}->('Valid Configuration Example', <<'EOT'); +paths: + "/": + mruby.handler: | + acl { + allow { addr == "127.0.0.1" } + deny + } + file.dir: /path/to/doc_root +EOT +?> + ++You can match an IP address against predefined list of address blocks using a script named trie_addr.rb. +
++Below is an example. +
+ += $ctx->{example}->('Address Block Matching Example', <<'EOT'); +paths: + "/": + mruby.handler: | + require "trie_addr.rb" + trie = TrieAddr.new.add(["192.168.0.0/16", "172.16.0.0/12"]) + acl { + allow { trie.match?(addr) } + deny + } + file.dir: /path/to/doc_root +EOT +?> + +
+This library currently supports only IPv4 addresses. TrieAddr#match?
returns false
when it receives an invalid IPv4 address (including an IPv6 address) as an argument..
+