Using variables on configuration (map?) for regex

Francis Daly francis at daoine.org
Mon Jul 25 18:42:17 UTC 2016


On Mon, Jul 25, 2016 at 10:41:43AM +0200, mostolog at gmail.com wrote:

Hi there,

> >(Your example suggests that your client will send a http header "Groups:
> >gfoo" if this request should be handled as if this user is in the group
> >gfoo. Perhaps you are using a special client configuration where that
> >is true?)
> We're using Apereo CAS. The "grouplist" header comes from a trusted
> server after user successfully authenticated.

Ok; I've read briefly about CAS, and I do not see how exactly the request
gets from the client to nginx.

But it sounds like the client does not have access to nginx directly;
instead it talks "through" the CAS system which adds this http header
to all requests.

That suggests that (a) nginx can entirely trust the content of the header;
and also (b) potentially the access control could be handled by the CAS
system instead of the nginx system.

(b) is not something to worry about right now, but may be a path towards
a solution if you cannot do what you want purely in nginx conf.

>     "There are rules to allow some groups to do specific actions on
> certain URLs". eg:
> 
>  * groupAll can GET on /asdf
>  * groupFoo can POST on /foo
>  * groupBar can POST on /bar
>    (again, names and locatiosn are just examples)
>  * groupBonus can DELETE on /foo

They are examples; but you do have (or have access to) the complete list
of groups, methods, and locations that are allowed access, somewhere?

See below...

> >>    map $request_method:$request_uri:$http_groups $denied {
> >>         default 1;
> >>         ~^GET:/content/$myvar:g$myvar 0;
> >>         ~^POST:/content/$myvar:admin$myvar 0;
> >>    }
> >That can't. You would need two lines per "myvar" value -- but since
> >you must have the list of myvar values somewhere, you should be able to
> >auto-generate these lines from that list.
> I didn't understand that.

"That can't" refers to "that map directive will not work as you wish,
because $myvar is not expanded in the first argument of each pair within
the block".

"two lines" was because previously the description was that "foo" meant
that "gfoo" could GET /content/foo and also that "adminfoo" could POST
/content/foo.

The rest of it refers to you knowing which groups are allowed which
access to which locations; and so you can use the example input above
to populate a map directive along the lines of:

  map $request_method:$http_groups:$request_uri $denied {
    default 1;
    ~^GET:groupAll:/asdf 0;
    ~^POST:groupFoo:/foo 0;
    ~^POST:groupBar:/bar 0;
    ~^DELETE:groupBonus:/foo 0;
  }

Having a few hundred lines like that should not be a problem for
"map" to read, and hopefully should not be a problem for you to write,
since it can be a mechanical export of whatever already has the list
of permissions. (And if there isn't something that has the list of
permissions, that might be the first thing to resolve.)

After than, in your server{} block, you could just do

  if ($denied) {
    return 403 "Forbidden";
  }

outside of all location{}s. Or you could limit it to the locations where
you want to control access -- the overall solution depends on the overall
requirements.

> >If the problem is "lots of files", then you could concatenate them all
> >in to one file.
> A kitty just died somewhere.

That suggests that your objection to "lots of files" is not related to
nginx having to open lots of files. (nginx is quite good at opening lots
of files, so long as your system allows it to happen.)

Perhaps your objection is related to you not wanting to write lots of
config? (nginx doesn't care - it doesn't write the config.) Or you not
wanting to read lots of config? (nginx is quite good at reading lots
of config, even if it looks like mostly-duplicate boilerplate.) Or
something else?

> foo.domain.com GET on certain URLs should be allowed for gfoo,
> gfoobar and gAdmin groups
> while POST on specific URLs, can be only executed by gfoo and gAdmin
> DELETE on some URLs only by gAdmin
> otherwise default is denied

Ok, so assuming that that set of method:group:url-prefix is complete,
I think I'm missing how it is not working with the previous suggestion.

Perhaps include $server_name or $host in the "map" definition if you
want to be explicit that (e.g) gfoo should not be able to GET /foo on
bar.domain.com; only on foo.domain.com.

(That was a piece that I had missed in my previous mail, where I suggested
turning the many maps into just one.)

> bar.domain.com share the "same" rules...the same way like
> asdf.domain.com, qwerty.domain.com and iloveyou.docmain.com
> 
> And here is it where I would like to use $variable, instead of
> copying a bunch of rules for each domain.

In nginx conf, a variable is a per-request expanded thing. A config-time
expandable thing should use a macro processor to turn it into as many
static things as are needed, and then let nginx read the static things.

In some cases, someone has written the code to use a $variable in a
directive. In the case of the "location" directive this has not happened,
and I suspect will not happen, in stock nginx.

What you are describing is, in nginx terms, the job of a macro
processor. Use the one you already know to generate the bunch of similar
rules. If the rules fragments are *identical*, you could use the nginx
"include" directive, which is about the limit of the built-in "macro"
processor. (That is to say: not a macro processor at all.)

> >Would a configuration along the lines of
> >
> >==
> >   server {
> >     location /content/ {
> >       if ($denied_group) {
> >         return 403 "Forbidden";
> >       }
> >       ...
> >     }
> >     location ~ /page/bar/action...and ~10 locations more per server...
> >   }
> >==
> >
> >do what you want?
> No, as it doesn't include the method POST/GET part, neither the
> groups allowed for each URL.

I thought that it did, assuming that the $denied_group variable is set
in the initial "map" definition.

Ah - I used "$denied" there and "$denied_group" here; sorry, typo/thinko
that was misleading.

>From the words I've seen, this looks like it should work. If not, I'm
happy to try guessing again.

Cheers,

	f
-- 
Francis Daly        francis at daoine.org



More information about the nginx mailing list