spring security and waffle negotiate with fallback to form login

1,277 views
Skip to first unread message

Andreas Fröhlich

unread,
Sep 1, 2014, 4:29:28 AM9/1/14
to waffle...@googlegroups.com
Hi group,

I've developed a simple hack to the waffle negotiate filter in order to have a fallback to a legacy form login in case the waffle sso negotiate fails, which I wanted to share.

My scenario was the following:
- existing legacy spring web application with a custom form login page authenticating against ldap and database fallback
- sso authentication
- requirement to have no browser popups for authentication requests (e.g. basic authentication, waffle ntlm, digest,...)

Following steps where performed to ensure a proper working setup before implementing the hack:
- Create custom form login for usage of spring security
- Ensure correct setup of spring security with all resources accessable only on authenticated except the form login page
- Waffle sso login as described in the various examples with kerberos, ntlm and basic authentication setup

After I came this far, I disabled the ntlm protocoll of the NegotiateSecurityFilterProvider in supplying the protocols property via spring configuration (e.g. '<property name="protocols" value="Negotiate"/>') as well as the BasicSecurityFilterProvider with commenting out the line in the SecurityFilterProviderCollection of the waffle configuration. This helped me avoid the client-side authentication popup windows requesting the user information. This then leads to the following behaviour - after the user calls up a restricted page having no prior authentication, he is authenticated as an anonymous user by spring security and the waffle NegotiateSecurityFilterProvider sends a 401 with a WWW-Authenticate header containing the value 'Negotiate'. The browser now reacts in either of two ways. If the 'Negotiate' protocol is available, it replies to conform with the requested protocol and the user will be authenticated via waffle. In case the protocol is not available, the browser stops since it cannot supply the information for the requested authentication challenge - which leads to a blank 401 page for the user.
The hack I applied to avoid a blank 401 is simply to extend the NegotiateSecurityFilterProvider and add content for redirecting to a fallback page in case the authentication fails. This looks something like this:

public class CustomNegotiateSecurityFilterProvider extends NegotiateSecurityFilterProvider {
    private String unauthorizedPage;

    /**
     * @see waffle.servlet.spi.NegotiateSecurityFilterProvider#NegotiateSecurityFilterProvider(waffle.windows.auth.IWindowsAuthProvider)
     */
    public CustomNegotiateSecurityFilterProvider(IWindowsAuthProvider auth) {
        super(auth);
    }

    /**
     * Returns the referral page in case the user is unauthorized.
     * @return The unauthorized page url.
     */
    public String getUnauthorizedPage() {
        return unauthorizedPage;
    }

    /**
     * Sets the referral page for the case the user is unauthorized.
     * @param unauthorizedPage The unauthorized page url.
     */
    public void setUnauthorizedPage(String unauthorizedPage) {
        this.unauthorizedPage = unauthorizedPage;
    }

    @Override
    public void sendUnauthorized(HttpServletResponse response) {
        super.sendUnauthorized(response);
        if (getUnauthorizedPage() != null && !getUnauthorizedPage().isEmpty()) {
            try {
                response.setContentType("text/html; charset=UTF-8");
                response.getOutputStream().print("<html><head><meta http-equiv='refresh' content='0; url=" + getUnauthorizedPage() + "' /></head><body>Redirection in progress...</body></html>");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

When replacing the NegotiateSecurityFilterProvider with the custom filter, the user will now be redirected on authentication failure and authenticated if the protocol can be fulfilled.

If any of you know of a better solution for this functionality I would be happy to hear.

Hope this helps someone...

Andreas

Daniel Doubrovkine

unread,
Sep 1, 2014, 8:08:21 PM9/1/14
to waffle...@googlegroups.com
I am surprised this works at all, but I believe you. Has it been reliable in a production environment?

The first problem I see is that its's possible that at this stage you're in the middle of the negotiate protocol, not at the end of it, so you're just redirecting the user away, while the browser is still able to supply a token that will end up being valid. There's no theoretical limit on how many times this send/receive exchange can happen, and in many cases it may actually be 2 roundtrips to the server.



--
You received this message because you are subscribed to the Google Groups "waffle" group.
To unsubscribe from this group and stop receiving emails from it, send an email to waffle-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

dB. | Moscow - Geneva - Seattle - New York
code.dblock.org - @dblockdotorg - artsy.net - github/dblock

Andreas Fröhlich

unread,
Sep 4, 2014, 3:45:11 AM9/4/14
to waffle...@googlegroups.com
I have done a little bit more testing and it works fine so far on firefox (31.0), chrome (36.0) and ie (11.0) with the exception of ie and chrome having popup windows for negotiate auth. This is different in firefox which does not try to supply negotiate when not present, but negotiate is active by default for chrome and ie anyways. The move into production will take place in the next few weeks, so I cannot say much to that yet.
Reply all
Reply to author
Forward
0 new messages