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