nginx-shib / nginx-http-shibboleth

Shibboleth auth request module for nginx
https://github.com/nginx-shib/nginx-http-shibboleth/wiki
Other
209 stars 27 forks source link

Persistent shib headers? #19

Closed eberhardtm closed 7 years ago

eberhardtm commented 7 years ago

I am attempting to replace apache with nginx using shibboleth as the authentication module for our CMS login. Our CMS depends on checking Shib-Session-ID on each request to confirm the user is logged in. If the user is logged in they can access the control panel otherwise they can just see the site.

Currently in our apache setup we have each vhost in its own root directory we'll call it /phpwebsite. There is a sub-directory /phpwebsite/secure that is set to require shibboleth authentication and there is an index.php that just redirect's them back to where they came from after authenticating with shibboleth. From there any requests in the form of /phpwebsite/some_location has the shib headers available. This is not the case with my nginx/shibboleth setup. The headers are there after the IDP redirect's back to /phpwebsite/secure and our CMS recognizes the user as logged in but any subsequent request to /phpwebsite/some_location is missing the shib headers. A test to /Shibboleth.sso/Session confirms the session is still active but without the headers the CMS doesn't know they are logged in. Is this the expected behavior or do I have a config issue?

Here is my nginx config:

location /phpwebsite {
    root /var/www;
    index index.php;
    try_files $uri $uri/ /index.php;

    location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        /etc/nginx/fastcgi_params;
    }

    location /phpwebsite/secure {
        include shib_clear_headers;
        include shib_fastcgi_params;
        #Add your attributes here. They get introduced as headers                                              
        #by the FastCGI authorizer so we must prevent spoofing.                                                
        more_clear_input_headers
                'displayName'
                'mail'
                'commonName';
        shib_request /shibauthorizer;
        shib_request_use_headers on;
    }
}

I tried using proxy_pass mysite.com/phpwebsite to redirect after authentication instead of letting the /phpwebsite/secure/index.php do it but I get the same results.

In apache my config was this:

alias /phpwebsite /path/to/document_root

<Location /phpwebsite>
    AuthType Shibboleth
    Require Shibboleth
</Location>

<Location /phpwebsite/secure>
    AuthType Shibboleth
    ShibRequestSetting requireSession 1
    ShibUseHeaders on
    Require valid-user
    Header unset ETag
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Location>

Versions and Systems

RHEL 7 php7 php-fpm nginx 1.11.10 shibd 2.6 Using your recommended shib setup with fastcgi build

davidjb commented 7 years ago

Okay, so the main issue here is that your configuration for /phpwebsite/some_location needs to be have shib_request /shibauthorizer enabled; in your current configuration, Shibboleth is only enabled for /phpwebsite/secure. At the moment, when a request comes in for that /phpwebsite/some_location, the shib FastCGI authorizer isn't being consulted and therefore not adding any headers/environment variables. To match your Apache configuration, you'd copy your nginx shib config up to the location /phpwebsite level, adjust your location /phpwebsite/secure settings (see below), and shift the Apache config for ShibRequestSetting requireSession 1 into your shibboleth2.xml.

Secondly, you're mixing the use of headers/parameters in your nginx location /phpwebsite/secure {} block. Unless you've got a really specific use-case, you don't want to mix their usage and just stick to either just headers or just parameters. Because you're using PHP/FastCGI, you (probably) want to avoid shib_request_use_headers on -- that sends Shib variables as headers, which can potentially be spoofed if you're not being careful. The safer and faster option is to use shib_request_set and fastcgi_param to populate just the Shib attributes you need into the FastCGI environment. See the first example under Configuration -- and you can see how you might adapt that if your backend application only needs to know about Shib-Session-ID and nothing else. Pick-and-choose what you want out of the shib_fastcgi_params file.

All that said, if your PHP application only reads from headers and not the environment, then you may be forced to use shib_request_use_headers. However, if you can, rewrite that part of your PHP code -- it'll make it much more secure. Lastly, if it isn't your code, do double-check that the application doesn't fallback from environment variables to headers automatically -- I had one PHP application that did that. It was trying to be helpful, but ended up causing a major security hole.

eberhardtm commented 7 years ago

First thanks for your quick reply!

I did try something similar by putting shib_request /shibauthorizer under the /phpwebsite location block and then having this config in my shibboleth2.xml

<RequestMapper type="XML">
  <RequestMap>                                                                                                 
    <Host scheme="https" name="mywebsite.com"
            authType="shibboleth"
            requireSession="true"
            redirectToSSL="443">
        <Path name="phpwebsite/secure" />
    </Host>                                                                                                    
  </RequestMap>
</RequestMapper>

However when I go to mywebsite.com/phpwebsite it will ask for shib authentication which is not what I want. I only want to authenticate when a user goes to /phpwebsite/secure but want the shib parameters available everywhere. I am assuming my shibboleth config is incorrect and its matching /phpwebsite as well as /phpwebsite/secure since it sounds like I should be able to replicate my apache behavior.

I'll keep playing with the shibb config.

I do have control over our CMS code base so I will look into re-coding the use of headers to use environment variables instead after I can get this working properly.

davidjb commented 7 years ago

The important bit to change is requireSession="true" -- having that forces authentication. At present, you've got that setting on your <Host>, which means it'll apply to all paths on that domain, not just the paths you have listed. It sounds like you'll want to move requireSession="true" down to be on <Path name="phpwebsite/secure" requireSession="true" /> (which inherits all the other settings from <Host>). The docs are a little technical, but take a look at https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMap; that explains just how the incoming request mapping takes place.

Good news is that it's all definitely possible; I do a similar thing (albeit with headers) for one of my applications. In short, anything configurable in Apache can be set up in shibboleth2.xml for use by the FastCGI authorizer -- at least anything I've tried/migrated so far. Debugging can be a challenge, but I'm told by another user you can get logging messages out by upping your logging levels.

Our project wiki's a work in process, but maybe https://github.com/nginx-shib/nginx-http-shibboleth/wiki/drupal might help get you started. LIkewise, if you wanted to contribute a wiki page when you're done, that'd be really helpful too.

eberhardtm commented 7 years ago

Ok I didn't realize I could put those in the path directive. That makes sense. Did alot of reading through the wiki yesterday and it seems what I need is passive authentication or a lazy session for /phpwebsite and active authentication for /phpwebsite/secure. Which my Require shibboleth in my apache config was doing. From what I gather the requireSession="false" in shibboleth2.xml should accomplish the lazy session. So I altered my config to reflect this and I set the . So now I get the behavior of logging in under the secure directory and not under the root directory. However, I still wasn't getting the full shib headers under /phpwebsite but I noticed I was getting one. HTTP_SHIB_HANDLER. I started watching the transcation.log and shibd.log and it seems my session is being removed for some reason. Every time I go to secure it creates a new session and then immediately removes it? But ofcourse the logs don't give any indication why its being removed. Doing more research now. As a sys admin with over 10 years experience shibboleth is making me feel pretty stupid right now...

eberhardtm commented 7 years ago

Damn it was my proxy_pass that was clearing my session. Its working now. Thanks for all the help.

davidjb commented 7 years ago

No problem, nice work. If you can share any insights or code snippets, PR about your implementation and documentation improvements are always welcome.

Closing this one off.