Search code examples
regexlaravelapache.htaccessshibboleth

Is Apache RewriteRule interfering with If and Location directives?


I'm using Apache to implement Shibboleth single sign on for a Laravel site. I'd like to bypass one specific subset of URLs from authentication (api/public, for example) so they're publicly accessible. For some reason the public folder's .htaccess file seems to be preventing this from working as expected.

I've tried this a bunch of different ways and all roads have lead to this same issue. Here's what I'm trying currently.

<Directory /var/www/html/mysite/public>
    SSLOptions +StdEnvVars
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    <If "%{REQUEST_URI} =~ m#api/public#">
        Require all granted
    </If>
    <Else>
        AuthType shibboleth
        ShibRequestSetting requireSession 1
        Require valid-user
    </Else>
</Directory>

Here's the .htaccess file that Laravel ships with:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>


    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

Unfortunately with the .htaccess file in place, the Else code is still getting executed and the Shib code runs. But I'm pretty sure the If condition is catching, because if throw in Require all denied as a test then it does forbid as expected.

If I remove the .htaccess however, this works! But it also means that any routing within Laravel is now broken, which I do need for this public-facing URL.

My best guess is that the .htaccess RewriteRule is causing the Else code to still run even after the If statement caught. Any suggestions on a way around this? Running into the same problem using Location directive.

Thanks.


Solution

  • Figured out a solution for this, will share here in case someone else runs into this. The issue was indeed that RewriteRule causes us to run through the whole thing again. The If stopped Shibboleth as expected the first time, but then we'd go through again after Laravel redirects us to index.php and pick it up anyway.

    Solved it by changing the Else to an ElseIf where we exclude index.php:

    <Directory /var/www/html/mysite/public>
        SSLOptions +StdEnvVars
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        <If "%{REQUEST_URI} =~ m#api/public#">
            Require all granted
        </If>
        <ElseIf "%{REQUEST_URI} !~ m#index\.php#">
            AuthType shibboleth
            ShibRequestSetting requireSession 1
            Require valid-user
        </ElseIf>
    </Directory>