• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.github/H26-Nov-2020-6648

includes/H26-Nov-2020-11593

t/H26-Nov-2020-323287

.gitignoreH A D26-Nov-202032 54

.travis.ymlH A D26-Nov-20201.7 KiB5655

CHANGES.rstH A D26-Nov-2020708 2720

CONFIG.rstH A D26-Nov-202015.8 KiB372289

LICENSEH A D26-Nov-20201.4 KiB2726

README.rstH A D26-Nov-202020.2 KiB444348

configH A D26-Nov-2020385 1310

ngx_http_shibboleth_module.cH A D26-Nov-202026.7 KiB978657

README.rst

1Shibboleth auth request module for Nginx
2========================================
3
4.. image:: https://travis-ci.org/nginx-shib/nginx-http-shibboleth.svg?branch=master
5   :target: https://travis-ci.org/nginx-shib/nginx-http-shibboleth
6
7This module allows Nginx to work with Shibboleth, by way of Shibboleth's
8FastCGI authorizer.  This module requires specific configuration in order to
9work correctly, as well as Shibboleth's FastCGI authorizer application
10available on the system.  It aims to be similar to parts of Apache's
11`mod_shib`_, though Shibboleth authorisation and authentication settings are
12configured via `shibboleth2.xml`_ rather than in the web server configuration.
13
14With this module configured against a ``location`` block, incoming requests
15are authorized within Nginx based upon the result of a subrequest to
16Shibboleth's FastCGI authorizer.  In this process, this module can be used to
17copy user attributes from a successful authorizer response into Nginx's
18original request as headers or environment parameters for use by any backend
19application.  If authorization is not successful, the authorizer response
20status and headers are returned to the client, denying access or redirecting
21the user's browser accordingly (such as to a WAYF page, if so configured).
22
23This module works at access phase and therefore may be combined with other
24access modules (such as ``access``, ``auth_basic``) via the ``satisfy``
25directive.  This module can be also compiled alongside
26``ngx_http_auth_request_module``, though use of both of these modules in the
27same ``location`` block is untested and not advised.
28
29Read more about the `Behaviour`_ below and consult `Configuration`_ for
30important notes on avoiding spoofing if using headers for attributes.
31
32For further information on why this is a dedicated module, see
33https://forum.nginx.org/read.php?2,238523,238523#msg-238523
34
35Directives
36----------
37
38The following directives are added into your Nginx configuration files. The
39contexts mentioned below show where they may be added.
40
41
42shib_request <uri>|off
43   | **Context:** ``http``, ``server``, ``location``
44   | **Default:** ``off``
45
46   Switches the Shibboleth auth request module on and sets URI which will be
47   asked for authorization.  The configured URI should refer to a Nginx
48   location block that points to your Shibboleth FastCGI authorizer.
49
50   The HTTP status and headers of the response resulting
51   from the sub-request to the configured URI will be returned to the user,
52   in accordance with the `FastCGI Authorizer specification`_.
53   The one (potentially significant) caveat is that due to the way
54   Nginx operates at present with regards to subrequests (what
55   an Authorizer effectively requires), the request body will *not* be
56   forwarded to the authorizer, and similarly, the response body from
57   the authorizer will *not* be returned to the client.
58
59   Configured URIs are not restricted to using a FastCGI backend
60   to generate a response, however.  This may be useful during
61   testing or otherwise, as you can use Nginx's built in ``return``
62   and ``rewrite`` directives to produce a suitable response.
63   Additionally, this module may be used with *any* FastCGI
64   authorizer, although operation may be affected by the above caveat.
65
66   .. warning::
67
68      The ``shib_request`` directive no longer requires the ``shib_authorizer``
69      flag.  This must be removed for Nginx to start. No other changes are
70      required.
71
72shib_request_set <variable> <value>
73   | **Context:** ``http``, ``server``, ``location``
74   | **Default:** ``none``
75
76   Set the ``variable`` to the specified ``value`` after the auth request has
77   completed. The ``value`` may contain variables from the auth request's
78   response.  For instance, ``$upstream_http_*``, ``$upstream_status``, and
79   any other variables mentioned in the `nginx_http_upstream_module
80   <https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables>`_
81   documentation.
82
83   This directive can be used to introduce Shibboleth attributes into the
84   environment of the backend application, such as `$_SERVER` for a FastCGI
85   PHP application and is the recommended method of doing so.  See the
86   `Configuration`_ documentation for an example.
87
88shib_request_use_headers on|off
89   | **Context:** ``http``, ``server``, ``location``
90   | **Default:** ``off``
91
92   .. note::
93
94      Added in v2.0.0.
95
96   Copy attributes from the Shibboleth authorizer response into the main
97   request as headers, making them available to upstream servers and
98   applications. Use this option only if your upstream/application does not
99   support server parameters via ``shib_request_set``.
100
101   With this setting enabled, Authorizer response headers beginning with
102   ``Variable-\*`` are extracted, stripping the ``Variable-`` substring from
103   the header name, and copied into the main request before it is sent to the
104   backend. For example, an authorizer response header such as
105   ``Variable-Commonname: John Smith`` would result in ``Commonname: John
106   Smith`` being added to the main request, and thus sent to the backend.
107
108   **Beware of spoofing** - you must ensure that your backend application is
109   protected from injection of headers. Consult the `Configuration`_ example
110   on how to achieve this.
111
112
113Installation
114------------
115
116This module can either be compiled statically or dynamically, since the
117introduction of `dynamic modules
118<https://www.nginx.com/resources/wiki/extending/converting/>`_ in Nginx
1191.9.11.  The practical upshot of dynamic modules is that they can be loaded,
120as opposed to static modules which are permanently present and enabled.
121
122The easiest way to obtain a packaged version of this module is to use the
123`pkg-oss <https://hg.nginx.org/pkg-oss/>`_ tool from Nginx, which provides for
124packaging of dynamic modules for installation alongside the official releases
125of Nginx from the `main repositories <https://nginx.org/en/download.html>`_
126and helps avoid the need to compile Nginx by hand.
127
128Otherwise, to compile Nginx with this module dynamically, pass the following
129option to ``./configure`` when building Nginx::
130
131    --add-dynamic-module=<path>
132
133You will need to explicitly load the module in your ``nginx.conf`` by
134including::
135
136    load_module /path/to/modules/ngx_http_shibboleth_module.so;
137
138and reload or restart Nginx.
139
140To compile Nginx with this module statically, pass the following option to
141``./configure`` when building Nginx::
142
143    --add-module=<path>
144
145With a static build, no additional loading is required as the module is
146built-in to Nginx.
147
148
149Configuration
150-------------
151
152For full details about configuring the Nginx/Shibboleth environment,
153see the documentation at
154https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/CONFIG.rst.
155
156An example ``server`` block consists of the following:
157
158.. code-block:: nginx
159
160    #FastCGI authorizer for Auth Request module
161    location = /shibauthorizer {
162        internal;
163        include fastcgi_params;
164        fastcgi_pass unix:/opt/shibboleth/shibauthorizer.sock;
165    }
166
167    #FastCGI responder
168    location /Shibboleth.sso {
169        include fastcgi_params;
170        fastcgi_pass unix:/opt/shibboleth/shibresponder.sock;
171    }
172
173    # Using the ``shib_request_set`` directive, we can introduce attributes as
174    # environment variables for the backend application. In this example, we
175    # set ``fastcgi_param`` but this could be any type of Nginx backend that
176    # supports parameters (by using the appropriate *_param option)
177    #
178    # The ``shib_fastcgi_params`` is an optional set of default parameters,
179    # available in the ``includes/`` directory in this repository.
180    #
181    # Choose this type of configuration unless your backend application
182    # doesn't support server parameters or specifically requires headers.
183    location /secure-environment-vars {
184        shib_request /shibauthorizer;
185        include shib_fastcgi_params;
186        shib_request_set $shib_commonname $upstream_http_variable_commonname;
187        shib_request_set $shib_email $upstream_http_variable_email;
188        fastcgi_param COMMONNAME $shib_commonname;
189        fastcgi_param EMAIL $shib_email;
190        fastcgi_pass unix:/path/to/backend.socket;
191    }
192
193    # A secured location. All incoming requests query the Shibboleth FastCGI authorizer.
194    # Watch out for performance issues and spoofing!
195    #
196    # Choose this type of configuration for ``proxy_pass`` applications
197    # or backends that don't support server parameters.
198    location /secure {
199        shib_request /shibauthorizer;
200        shib_request_use_headers on;
201
202        # Attributes from Shibboleth are introduced as headers by the FastCGI
203        # authorizer so we must prevent spoofing. The
204        # ``shib_clear_headers`` is a set of default header directives,
205        # available in the `includes/` directory in this repository.
206        include shib_clear_headers;
207
208        # Add *all* attributes that your application uses, including all
209        #variations.
210        more_clear_input_headers 'displayName' 'mail' 'persistent-id';
211
212        # This backend application will receive Shibboleth variables as request
213        # headers (from Shibboleth's FastCGI authorizer)
214        proxy_pass http://localhost:8080;
215    }
216
217Note that we use the `headers-more-nginx-module
218<https://github.com/openresty/headers-more-nginx-module>`_ to clear
219potentially dangerous input headers and avoid the potential for spoofing.  The
220latter example with environment variables isn't susceptible to header
221spoofing, as long as the backend reads data from the environment parameters
222**only**.
223
224A `default configuration
225<https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/includes/shib_clear_headers>`_
226is available to clear the basic headers from the Shibboleth authorizer, but
227you must ensure you write your own clear directives for all attributes your
228application uses.  Bear in mind that some applications will try to read a
229Shibboleth attribute from the environment and then fall back to headers, so
230review your application's code even if you are not using
231``shib_request_use_headers``.
232
233
234With use of ``shib_request_set``, a `default params
235<https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/includes/shib_fastcgi_params>`_
236file is available which you can use as an nginx ``include`` to ensure all core
237Shibboleth variables get passed from the FastCGI authorizer to the
238application. Numerous default attributes are included so remove the ones that
239aren't required by your application and add Federation or IDP attributes that
240you need. This default params file can be re-used for upstreams that aren't
241FastCGI by simply changing the ``fastcgi_param`` directives to
242``uwsgi_param``, ``scgi_param`` or so forth.
243
244Gotchas
245~~~~~~~
246
247* Subrequests, such as the Shibboleth auth request, aren't processed through header filters.
248  This means that built-in directives like ``add_header`` will **not** work if configured
249  as part of the a ``/shibauthorizer`` block.  If you need to manipulate subrequest headers,
250  use ``more_set_headers`` from the module ``headers-more``.
251
252  See https://forum.nginx.org/read.php?29,257271,257272#msg-257272.
253
254Behaviour
255---------
256
257This module follows the `FastCGI Authorizer specification`_ where possible,
258but has some notable deviations - with good reason.  The behaviour is thus:
259
260* An authorizer subrequest is comprised of all aspects of the original
261  request, excepting the request body as Nginx does not support buffering of
262  request bodies.  As the Shibboleth FastCGI authorizer does not consider the
263  request body, this is not an issue.
264
265* If an authorizer subrequest returns a ``200`` status, access is allowed.
266
267  If ``shib_request_use_headers`` is enabled, and response headers beginning
268  with ``Variable-\*`` are extracted, stripping the ``Variable-`` substring
269  from the header name, and copied into the main request.  Other authorizer
270  response headers not prefixed with ``Variable-`` and the response body are
271  ignored.  The FastCGI spec calls for ``Variable-*`` name-value pairs to be
272  included in the FastCGI environment, but we make them headers so as they may
273  be used with *any* backend (such as ``proxy_pass``) and not just restrict
274  ourselves to FastCGI applications.  By passing the ``Variable-*`` data as
275  headers instead, we end up following the behaviour of ``ShibUseHeaders On``
276  in ``mod_shib`` for Apache, which passes these user attributes as headers.
277
278  In order to pass attributes as environment variables (the equivalent to
279  ``ShibUseEnvironment On`` in ``mod_shib``), attributes must be manually
280  extracted using ``shib_request_set`` directives for each attribute.  This
281  cannot (currently) be done *en masse* for all attributes as each backend may
282  accept parameters in a different way (``fastcgi_param``, ``uwsgi_param``
283  etc).  Pull requests are welcome to automate this behaviour.
284
285* If the authorizer subrequest returns *any* other status (including redirects
286  or errors), the authorizer response's status and headers are returned to the
287  client.
288
289  This means that on ``401 Unauthorized`` or ``403 Forbidden``, access will be
290  denied and headers (such as ``WWW-Authenticate``) from the authorizer will be
291  passed to client.  All other authorizer responses (such as ``3xx``
292  redirects) are passed back to the client, including status and headers,
293  allowing redirections such as those to WAYF pages and the Shibboleth
294  responder (``Shibboleth.sso``) to work correctly.
295
296  The FastCGI Authorizer spec calls for the response body to be returned to
297  the client, but as Nginx does not currently support buffering subrequest
298  responses (``NGX_HTTP_SUBREQUEST_IN_MEMORY``), the authorizer response body
299  is effectively ignored.  A workaround is to have Nginx serve an
300  ``error_page`` of its own, like so:
301
302  .. code-block:: nginx
303
304      location /secure {
305         shib_request /shibauthorizer;
306         error_page 403 /shibboleth-forbidden.html;
307         ...
308      }
309
310  This serves the given error page if the Shibboleth authorizer denies the
311  user access to this location.  Without ``error_page`` specified, Nginx will
312  serve its generic error pages.
313
314  Note that this does *not* apply to the Shibboleth responder (typically hosted at
315  ``Shibboleth.sso``) as it is a FastCGI responder and Nginx is fully compatible
316  with this as no subrequests are used.
317
318  For more details, see https://forum.nginx.org/read.php?2,238444,238453.
319
320Whilst this module is geared specifically for Shibboleth's FastCGI authorizer,
321it will likely work with other authorizers, bearing in mind the deviations
322from the spec above.
323
324Tests
325-----
326
327Tests are automatically run on Travis CI (using `this configuration
328<https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/.travis.yml>`_)
329whenever new commits are made to the repository or when new pull requests
330are opened. If something breaks, you'll be informed by Travis and the results
331will be reported on GitHub.
332
333Tests are written using a combination of a simple Bash script in `.travis.yml`
334for compilation of different versions of Nginx with our module, and also the
335`Test::Nginx <https://metacpan.org/pod/Test::Nginx::Socket>`_ Perl test
336scaffolding for integration testing with this module.  Consult the previous
337link for information on how to extend the tests, and also refer to the
338underlying `Test::Base
339<https://metacpan.org/pod/Test::Base#blocks-data-section-name>`_ documentation
340on aspects like the `blocks()` function.
341
342Integration tests are run automatically with Travis CI but
343also be run manually (requires Perl & CPAN to be installed):
344
345.. code-block:: bash
346
347    cd nginx-http-shibboleth
348    cpanm --notest --local-lib=$HOME/perl5 Test::Nginx
349    # nginx must be present in PATH and built with debugging symbols
350    PERL5LIB=$HOME/perl5/lib/perl5 prove
351
352Help & Support
353--------------
354
355Support requests for Shibboleth configuration and Nginx or web server setup
356should be directed to the Shibboleth community users mailing list.  See
357https://www.shibboleth.net/community/lists/ for details.
358
359Debugging
360---------
361
362Because of the complex nature of the nginx/FastCGI/Shibboleth stack, debugging
363configuration issues can be difficult.  Here's some key points:
364
365#. Confirm that ``nginx-http-shibboleth`` is successfully built and installed
366   within nginx. You can check by running ``nginx -V`` and inspecting the
367   output for ``--add-module=[path]/nginx-http-shibboleth`` or
368   ``--add-dynamic-module=[path]/nginx-http-shibboleth``.
369#. If using dynamic modules for nginx, confirm you have used the
370   ``load_module`` directive to load this module.  Your use of ``shib_request``
371   and other directives will fail if you have forgotten to load the module.
372#. If using a version of nginx that is different to those we
373   `test with <https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/.travis.yml>`_
374   or if you are using other third-party modules, you should run
375   the test suite above to confirm compatibility.  If any tests fail, then check
376   your configuration or consider updating your nginx version.
377#. Shibboleth configuration: check your ``shibboleth2.xml`` and associated
378   configuration to ensure your hosts, paths and attributes are being correctly
379   released.  An `example configuration <https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/CONFIG.rst#configuring-shibboleths-shibboleth2xml-to-recognise-secured-paths>`_
380   can help you identify key "gotchas" to configuring ``shibboleth2.xml`` to work
381   with the FastCGI authorizer.
382#. Application-level: within your code, always start with the simplest possible
383   debugging output (such as printing the request environment) and work
384   up from there.  If you want to create a basic, stand-alone app, take
385   a look at the `Bottle <https://github.com/nginx-shib/nginx-http-shibboleth/wiki/bottle>`_
386   configuration on the wiki.
387#. Debugging module internals: if you've carefully checked all of the above, then
388   you can also debug the behaviour of this module itself.  You will need to have
389   compiled nginx with debugging support (via ``./auto/configure --with-debug ...``)
390   and when running nginx, it is easiest if you're able run in the foreground with
391   debug logging enabled.  Add the following to your ``nginx.conf``:
392
393   .. code-block:: nginx
394
395      daemon off;
396      error_log stderr debug;
397
398   and run nginx.  Upon starting nginx you should see lines containing `[debug]` and
399   as you make requests, console logging will continue.  If this doesn't happen,
400   then check your nginx configuration and compilation process.
401
402   When you eventually make a request that hits (or should invoke) the
403   ``shib_request`` location block, you will see lines like so in the output:
404
405   .. code-block:: nginx
406
407      [debug] 1234#0: shib request handler
408      [debug] 1234#0: shib request set variables
409      [debug] 1234#0: shib request authorizer handler
410      [debug] 1234#0: shib request authorizer allows access
411      [debug] 1234#0: shib request authorizer copied header: "AUTH_TYPE: shibboleth"
412      [debug] 1234#0: shib request authorizer copied header: "REMOTE_USER: john.smith@example.com"
413      ...
414
415   If you don't see these types of lines containing `shib request ...`,
416   or if you see *some* of the lines above but not where headers/variables are being
417   copied, then double-check your nginx configuration.  If you're still not getting
418   anywhere, then you can add your own debugging lines into the source (follow
419   this module's examples) to eventually determine what is going wrong and when.
420   If doing this, don't forget to recompile nginx and/or ``nginx-http-shibboleth``
421   whenever you make a change.
422
423If you believe you've found a bug in the core module code, then please
424`create an issue <https://github.com/nginx-shib/nginx-http-shibboleth/issues>`_.
425
426You can also search existing issues as it is likely someone else has
427encountered a similar issue before.
428
429Versioning
430----------
431
432This module uses `Semantic Versioning <https://semver.org/>`_ and all releases
433are tagged on GitHub, which allows package downloads of individual tags.
434
435License
436-------
437
438This project is licensed under the same license that nginx is, the
439`2-clause BSD-like license <https://github.com/nginx-shib/nginx-http-shibboleth/blob/master/LICENSE>`_.
440
441.. _FastCGI Authorizer specification: https://web.archive.org/web/20160306081510/http://fastcgi.com/drupal/node/6?q=node/22#S6.3
442.. _mod_shib: https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPApacheConfig
443.. _shibboleth2.xml: https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPShibbolethXML
444