Info |
---|
tl;dr: You can have Nginx with Shibboleth. Rebuild Shibboleth with FastCGI support, and recompile Nginx with a custom module: https://bitbucketgithub.orgcom/davidjb/ngx_http_auth_request_modulenginx-shib/nginx-http-shibboleth. You can now run the Shibboleth FastCGI authorizer and responder applications and successfully authenticate! |
Note | ||
---|---|---|
| ||
There are also changes in 1.5+ that see the Auth Request module being directly included in the core of Nginx. It is not built by default at present, but its inclusion will make the integration process marginally easier in time. |
Table of Contents |
---|
Background
There are a lot of existing posts around the web asking about integrating Shibboleth and Nginx, and until now, the answer was that there was no solution. This is a summary of the background information gathered to date:
- Shibboleth SP supports Apache and IIS by default, but not Nginx.
- The closest level of support is via FastCGI, which Shibboleth does have but the default distribution needs to be rebuilt to support it.
- Nginx has support for FastCGI responders, but not for FastCGI authorizers.
This last point is where things get interesting. Via a plugin, Nginx does have support for sub-requests for allowing access, and the Auth Request module gets very close in terms of providing the functionality required for a FastCGI authorizer. However, that module, in its vanilla state, only allows for the sub-request to respond with an allow or deny response. However, some minor changes, which can be found in a patched version of that module allows the auth request to roughly follow the specification.
Cautionary Note
The custom Auth Request module for Nginx doesn’t presently feature support for sending the original request body to the FastCGI authorizer, and likewise, doesn’t support sending the authorizer’s response body back to the client. For Shibboleth authorisation, however, these two are inconsequential as only HTTP redirections and HTTP headers (cookies) are used for authentication to succeed.
Contributions are welcome at the above repository. I’m currently looking to have my improvements merged back into the main plugin, too.
Install the Shibboleth SP with FastCGI support
The Shibboleth SP may or may not be built with FastCGI support by default. For information about how to rebuild packages on Linux, see the blog post at Shibboleth and FastCGI. It will step you though either how to install or build the Shibboleth SP for your system and get the FastCGI applications up and running.
Once you’re done, make a note of the socket where the applications can be accessed. This information will be utilised shortly.
Compile Nginx with FastCGI Authorizer support
The next step is sorting out Nginx with suitable support for FastCGI authorizers. As mentioned above, I was able to delve into Nginx and make a patched version of that Auth Request module allows the auth request to follow the specification (see caveat above about request/response bodies).
Compile Nginx with the custom Auth request module and the Headers More module (take a look at https://github.com/jcu-eresearch/nginx-custom-build for how) or if you’re on RHEL or CentOS 6 and trust my RPM building skills, then install from this RPM repository:
You can either install the RPMs manually, or add it as another repository for Yum to use:
[jcu-eresearch] name=JCU eResearch Custom Repo baseurl=https://www.hpc.jcu.edu.au/rpm/ gpgcheck=0 enabled=1 priority=1
You should probably ensure that your other Nginx repo has a lower priority (such as priority=2) so it doesn’t take precedence over these custom packages.
Once you’ve successfully got Nginx compiled with my custom auth request module, then you’re ready to configure it all up.
Configure one or more servers within your Nginx configuration like so. You’ll need the socket information for your FastCGI Shibboleth SP applications.
server { listen 443 ssl; ... #FastCGI authorizer for Auth Request module
location = /shibauthorizer { internal; include fastcgi_params; fastcgi_pass unix:/opt/shibboleth/shibauthorizer.sock; } #FastCGI responder for SSO
location /Shibboleth.sso { include fastcgi_params; fastcgi_pass unix:/opt/shibboleth/shibresponder.sock; } #Resources for the Shibboleth error pages. This can be customised.
location /shibboleth-sp { alias /usr/share/shibboleth/; } #A secured location. Here all incoming requests query the
#FastCGI authorizer. Watch out for performance issues and spoofing.
location /secure { more_clear_input_headers 'Variable-*' 'Shib-*' 'Remote-User' 'REMOTE_USER' 'Auth-Type' 'AUTH_TYPE'; #Add your attributes here. They get introduced as headers
#by the FastCGI authorizer so we must prevent spoofing.
more_clear_input_headers 'displayName' 'mail' 'persistent-id'; auth_request /shibauthorizer authorizer=on; proxy_pass http://localhost:8080; } #A secured location, but only a specific sub-path causes Shibboleth
#authentication.
location /secure2 { proxy_pass http://localhost:8080; location = /secure2/shibboleth { more_clear_input_headers 'Variable-*' 'Shib-*' 'Remote-User' 'REMOTE_USER' 'Auth-Type' 'AUTH_TYPE'; #Add your attributes here. They get introduced as headers
#by the FastCGI authorizer so we must prevent spoofing.
more_clear_input_headers 'displayName' 'mail' 'persistent-id'; auth_request /shibauthorizer authorizer=on; proxy_pass http://localhost:8080; } } }An explanation about the above is provided in the comments. I should note that:
The first 3 locations are pure boilerplate for any host that requires Shibboleth authentication, so you can (and should!) put these into an include-able configuration file and reuse them.
The /shibboleth-sp location is purely there to help your default install. If you customise your error pages, feel free to change or delete this location.
Take note of the more_clear_input_headers calls. As the Shibboleth authorizer will inject headers into the request before passing the request onto the final upstream endpoint, you must use these directives to protect from spoofing. You should expand the second call to this directive when you have more incoming attributes from the Shibboleth authorizer. Or else beware…
The /secure location will ask the FastCGI authorizer for attributes for every request that comes in. This may or may not be what you want. Keep in mind this means that each request will have Shibboleth attributes dropped into the request for sending onto backend services, and this will happen every time. Since this for every request you may wish to reconsider a lighter-weight strategy, if your backend application supports it.
The /secure2 location only asks the FastCGI authorizer for auth on a (very) specific sub-path. Only upon the user hitting this specific URL will the authentication process be triggered. This is a smarter authentication technique to avoid extra overhead — set the upstream for the specific sub-path to be somewhere an application session is created, and have that application session capture the Shibboleth attributes.
Notice how the rest of the application doesn’t refer to the authorizer. This means the application can be used anonymously, too. Alternatively, you can configure the requireSession option to be fa
Adding the auth_request line into a location isn’t all you need to do to get the FastCGI authorizer to recognise your path as Shibboleth protected. You need to follow the instructions below and take care.
Save the configuration and follow the next section. You’re almost done.
Configuring Shibboleth to recognise secured paths
Typically, within Apache, you can tell Shibboleth which paths to secure by using something like:
<Location /secure> ShibRequestSetting authType shibboleth ShibRequestSetting requireSession false </Location>
However, the FastCGI authorizer for Shibboleth operates without such directives and thus path protection needs to be configured like it would be for IIS, using the <RequestMapper> configuration. The same options are accepted within this section of the shibboleth2.xml configuration file, it’s just that you need to know where to put them. So let’s do that.
Configure your shibboleth2.xml file like so. Find the RequestMapper element and replace it with something like the following:
<RequestMapper type="XML"> <RequestMap> <Host name="eresearch.jcu.edu.au" authType="shibboleth" requireSession="true" redirectToSSL="443"> <Path name="/secure" /> <Path name="/secure2/shibboleth" /> ... </Host> ... </RequestMap> </RequestMapper>
Some notes:
The Shibboleth FastCGI authorizer needs to see authType and requireSession configured for the resultant path. If they are not present, then the authorizer will ignore the path it is passed and the user will not be prompted for authentication (and you will tear your hair out because no logging takes place!).
<Path> names are case sensitive here. You have hereby been warned! — although this shouldn’t be too surprising to you hopefully.
You can use other configuration items like <HostRegex> and <PathRegex> and <AccessControl> to configure what happens to requests. Check out the documentation below - there’s lots to learn.
An interesting aspect here is that configuration is inherited downwards in the XML tree. So, you could configure something like the authType on a <Host> and have it apply to all paths beneath it.
You don’t need to do this, though. You may put all the configuration attributes onto the <Path> element, or even move them up to higher levels in the tree if you want to reduce duplication.
Nested <Path> elements will see their path segments being greedy. So putting a path with name=”shibboleth”within a path with name=”secure” really translates to a path with name=”secure/shibboleth”. Whatever takes your fancy here.
Once you’re done, then restart the Shibboleth daemon, ensure that you restart the Shibboleth FastCGI applications, and hard restart Nginx just to make sure it finds those sockets:
service shibd restart supervisorctl restart shibauthorizer shibresponder service nginx restart
Assuming, of course, that you’re using Supervisor to run your applications. You should. It’s easy to work with and fun.
Try loading up your Shibboleth protected URL. If all goes well, then you should get a complete authentication cycle. If not, check carefully through everything above.
Take a look at NativeSPRequestMapper and NativeSPRequestMap for more information.
Warnings
Remember these things:
- The Shibboleth authorizer requires a <Path> or <PathRegex> to be correctly configured with authType and requireSession for auth to take place. If you don’t (or you do and forget to restart shibd), then the authorizer will blindly return a 200 OK status response, which equates to blindly allowing access.
- No logs will get issued anywhere by the way for anything related to the FastCGI applications (standard shibd logging does apply, however) so if you’re testing for why the redirect cycle doesn’t start, try killing your FastCGI authorizer and make sure you see a 502 error come back. If you still get a 200, then your auth_request configuration in Nginx is probably wrong and the authorizer isn’t being contacted.
- When in doubt, hard restart the entire stack, and use something like curl to avoid browser caching.
Conclusion
That was an effort, wasn’t it. Please feel free to help out with this documentation or help improve some of this process.
If you’re skilled in the ways of Nginx, or else would (could) like to learn, I’d like to improve on the work I’ve done with the auth request module and hopefully formalise the features into inclusion in Nginx's core. This may not be possible as some of the manner in which the custom Authorizer works is actually specific to this application, but it's worth looking into.
...
Full information on how to include the ngnix-http-shibboleth custom module with Nginx are provided on GitHub. This repository now serves as the canonical place for all documentation in this space.