Skip to content

Latest commit

 

History

History
239 lines (192 loc) · 11.2 KB

SpringSecuritySingleSignOnFilter.md

File metadata and controls

239 lines (192 loc) · 11.2 KB

Spring Security Single-SignOn Filter

The Waffle Spring-Security Filter implements the Negotiate and Basic protocols with Kerberos and NTLM single sign-on support for web applications that utilize Spring-Security. This allows users to browse to a Windows intranet site without having to re-enter credentials for browsers that support Kerberos or NTLM and to fall back to Basic authentication for those that do not. For more information about Spring-Security see here. NOTE: Also available with delegation to support authentication for the service provider [here] (https://github.com/dblock/waffle/blob/master/Docs/spring/DelegatingSpringSecuritySingleSignOnFilter.md) Configuring Spring Security

The following steps are required to configure a web server with the Waffle Spring-Security Filter.

We'll assume that Spring-Security is configured via web.xml with a filter chain and a Spring context loader listener. The Waffle beans configuration will be added to waffle-filter.xml.

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/waffle-filter.xml</param-value> 
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Copy Waffle JARs, including waffle-jna.jar, caffeine.jar, jna.jar, jna-platform.jar, slf4j-api.jar and waffle-spring-security5.jar in the application's lib directory along with Spring and Spring-Security JARs. Or, if you use Maven, add the following to your pom.xml:

  • Use specific versions as bundled in waffle-distro
<dependency>
    <groupId>com.github.dblock.waffle</groupId>
    <artifactId>waffle-spring-security4</artifactId>
    <version>${waffle.version}</version>
</dependency>

Declare a Windows Authentication provider. This is the link between Waffle and the operating system.

<bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl" />

Declare a collection of Waffle security filter providers that implement various authentication protocols.

<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
</bean>

<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
</bean>

<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
    <constructor-arg>
        <list>
            <ref bean="negotiateSecurityFilterProvider" />
            <ref bean="basicSecurityFilterProvider" />
        </list>
    </constructor-arg>
</bean>

Add the Waffle security filter and entry point to the sec:http configuration section. The filter will be placed before the BASIC authentication filter that ships with Spring-Security. The filter uses the collection of authentication filter providers defined above to perform authentication.

<sec:http entry-point-ref="negotiateSecurityFilterEntryPoint">
    <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
    <sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>

<bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
    <property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>

Define a required default Spring-Security authentication manager.

<sec:authentication-manager alias="authenticationProvider" />

Define a Spring-Security filter that uses the collection of security filter providers to perform authentication.

<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
    <property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>

Granted Authorities

Upon successful login, Waffle will populate Spring Security's Authentication instance with GrantedAuthority objects.

By default, Waffle will populate the Authentication instance with the following GrantedAuthority objects:

  • A GrantedAuthority with the string ROLE_USER.
  • One GrantedAuthority per group to which the user belongs. The GrantedAuthority strings will be the uppercase group name prefixed with ROLE_. For example, if a user is a member of the Everyone group, he obtains the ROLE_EVERYONE granted authority.

The default behavior can be changed by configuring a different defaultGrantedAuthority and grantedAuthorityFactory on the waffleNegotiateSecurityFilter object.

Security Filter Options

The waffleNegotiateSecurityFilter bean can be configured with the following options.

  • principalFormat: Specifies the name format for the principal.
  • roleFormat: Specifies the name format for the role.
  • allowGuestLogin: Allow guest login. When true and the system's Guest account is enabled, any invalid login succeeds as Guest. Note that while the default value of allowGuestLogin is true, it is recommended that you disable the system's Guest account to disallow Guest login. This option is provided for systems where you don't have administrative privileges.
  • impersonate: Allow impersonation. When true the remote user will be impersonated. Note that there is no mapping between the Windows native threads, under which the impersonation takes place, and the Java threads. Thus you'll need to use Windows native APIs to perform impersonated actions. Any action done in Java will still be performed with the user account running the servlet container.
  • defaultGrantedAuthority: Specifies the GrantedAuthority to be added to every successfully authenticated user. By default, the defaultGrantedAuthority will add a GrantedAuthority for ROLE_USER. If you do not want this behavior, you can set the defaultGrantedAuthority to null (if you do not want a GrantedAuthority to be added by default), or some other GrantedAuthority.
  • grantedAuthorityFactory: Used to create GrantedAuthority objects for each of the groups to which the authenticated user belongs. The default grantedAuthorityFactory will construct GrantedAuthority objects whose string is the uppercase group name prefixed with ROLE_.
<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
    <property name="Provider" ref="waffleSecurityFilterProviderCollection" />
    <property name="AllowGuestLogin" value="false" />
    <property name="Impersonate" value="true" />
    <property name="PrincipalFormat" value="fqn" />
    <property name="RoleFormat" value="both" />
</bean>

Security Filter Provider Collection Options

The waffleSecurityFilterProviderCollection bean can be constructed with a list of available security filter providers. Waffle supplies a Negotiate and a BASIC authentication security filter provider. In addition, each provider may implement more options.

<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
    <constructor-arg>
        <list>
            <ref bean="negotiateSecurityFilterProvider" />
            <ref bean="basicSecurityFilterProvider" />
        </list>
    </constructor-arg>
</bean>

Negotiate Security Filter Provider Options

The negotiateSecurityFilterProvider bean supports a list of protocols. Choose one or the combination of Negotiate and NTLM.

<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
    <property name="protocols">
        <list>
            <value>Negotiate</value>
            <value>NTLM</value>
        </list>
    </property>
</bean>

Basic Security Filter Provider Options

The basicSecurityFilterProvider bean supports a custom Basic authentication Realm name.

<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
    <constructor-arg ref="waffleWindowsAuthProvider" />
    <property name="realm" value="DemoRealm" />
</bean>

Mixed Single-SignOn and Form

To support both single sign-on and form-based authentication with spring security similarly to TomcatMixedSingleSignOnAndFormAuthenticatorValve.

Split single sign-on and form based authentication in dedicated entry point configurations:

<sec:http pattern="/waffle" entry-point-ref="negotiateSecurityFilterEntryPoint">
    <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
    <sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>

<sec:http>
    <sec:intercept-url pattern="/login.jsp" access="permitAll" />
    <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?error=true"/>
    <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
</sec:http>

<sec:authentication-manager alias="authenticationProvider">
		  <sec:authentication-provider ref="waffleSpringAuthenticationProvider" />
</sec:authentication-manager>

<bean id="waffleSpringAuthenticationProvider" class="waffle.spring.WindowsAuthenticationProvider">
    <property name="authProvider" ref="waffleWindowsAuthProvider" />
</bean>

Create a login page based on the following code. There're two requirements for the login form. The form-based authentication must post to the login processing url location. The single sign-on link must redirect to the single sign-on entry point path.

<form method="POST" name="loginform" action="<%=request.getContextPath()%>/login">
<table style="vertical-align: middle;">
    <tr>
        <td>Username:</td>
        <td><input type="text" name="username" /></td>
    </tr>
    <tr>
        <td>Password:</td>
        <td><input type="password" name="password" /></td>
    </tr>
    <tr>
        <td><input type="submit" value="Login" /></td>
    </tr>
</table>
</form>
<hr>
<a href="<%=request.getContextPath()%>/waffle">
   Login (Negotiate)
</a>

Defining the redirection after a successful single sign-on authentication can be achieved by registering a redirect servlet with "/waffle" url-mapping:

@WebServlet("/waffle")
public class RedirectServlet extends HttpServlet {
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/index.jsp"));
	}
}

Waffle Spring-Security Demo

A demo application can be found in the Waffle distribution in the Samples\waffle-spring-filter directory. Copy the entire directory into Tomcat's or Jetty's webapps directory and navigate to http://localhost:8080/waffle-spring-filter/.