This is the sample to integrate SSO to Java web app with spring security, typical authentication process:
In this case, Web app sever is not proxyed, and recieve request directly, so the user's request arrive to Web app server firstly
![](http://dl2.iteye.com/upload/attachment/0118/8617/b986decd-5d80-3e48-bc95-2a924ab06067.jpg)
Core Spring security config:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <sec:http pattern="/assets/**" security="none" /> <sec:http pattern="/views/logout**" security="none" /> <bean id="userDetailsService" class="com.wilson.security.CustomUserDetailsService" /> <sec:http entry-point-ref="loginHandler" use-expressions="true" auto-config="false" request-matcher="regex"> <sec:intercept-url pattern="/**" access="isAuthenticated()" /> <sec:logout logout-url="/logout" invalidate-session="true" success-handler-ref="logoutHandler" /> <sec:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" /> </sec:http> <bean id="loginHandler" class="com.wilson.security.SSOLoginHandler"> <property name="loginFormUrl" value="${sso.proxy}" /> <property name="authProcessingURL" value="http://${fqdn}:${port}${context}/authenticate" /> </bean> <bean id="logoutHandler" class="com.wilson.security.SSOLogoutHandler"> <property name="defaultTargetUrl" value="/views/logout.jsp" /> <property name="alwaysUseDefaultTargetUrl" value="true" /> </bean> <bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <constructor-arg value="/views/logout-failure.jsp"></constructor-arg> </bean> <bean id="authenticationFilter" class="com.wilson.security.SSOAuthenticationFilter"> <property name="filterProcessesUrl" value="/authenticate" /> <property name="authenticationManager" ref="authenticationManager" /> <property name="AuthenticationFailureHandler" ref="authenticationFailureHandler" /> <property name="publicKey" value="${sso.publickey}" /> </bean> <sec:authentication-manager alias="authenticationManager"> <sec:authentication-provider user-service-ref="userDetailsService" /> </sec:authentication-manager> </beans>
So, first, we need to add a custom LoginUrlAuthenticationEntryPoint to redirect request to SSO when user open home page without login
public class SSOLoginHandler extends LoginUrlAuthenticationEntryPoint { private final Logger logger = LoggerFactory.getLogger(SSOLoginHandler.class); private String authProcessingURL; @Override public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authenticationException) throws IOException, ServletException { logger.debug("Preparing redirectiion to SSO PROXY..."); // new DefaultRedirectStrategy().sendRedirect(request, response, this.getLoginFormUrl() + "?ref=" // + authProcessingURL); String SSO_LOGIN_URL= "https://ssoserver.com/sso.jsp"; new DefaultRedirectStrategy().sendRedirect(request, response, SSO_LOGIN_URL + "?ref=" + authProcessingURL); } public String getAuthProcessingURL() { return authProcessingURL; } public void setAuthProcessingURL(final String authProcessingURL) { this.authProcessingURL = authProcessingURL; }
Simplete logout which do some logging items..
public class SSOLogoutHandler extends SimpleUrlLogoutSuccessHandler { private final Logger logger = LoggerFactory.getLogger(SSOLogoutHandler.class); @Override public void onLogoutSuccess(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException, ServletException { super.onLogoutSuccess(request, response, authentication); logger.debug("Performing an SSO logout at: {}", this.getDefaultTargetUrl()); } }
Custom UserDeatailsService to load role and Grant Authority to user
public class CustomUserDetailsService implements UserDetailsService { public static final String DEFAULT_AUTH_PASSWORD = "password"; @Override public UserDetails loadUserByUsername(String soeid) throws UsernameNotFoundException { List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>(); grantedAuths.add(new SimpleGrantedAuthority(***Service.queryUserRoleFromDatabase(soeid).toString())); UserDetails user = new User(soeid, DEFAULT_AUTH_PASSWORD, true, true, true, true, grantedAuths); return user; } }
Custom authetication filter to processe the response form SSO server after logicn
public class SSOAuthenticationFilter extends UsernamePasswordAuthenticationFilter { public static final String DEFAULT_AUTH_PASSWORD = "password"; private final Logger logger = LoggerFactory.getLogger(SSOAuthenticationFilter.class); private Cipher cipher; public SSOAuthenticationFilter() { super.setPostOnly(false); // allow a GET request from SSO PROXY } @Override public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response) throws AuthenticationException { String[] sid = decodeSID(request); String soeid = sid[0]; // token is expired if currentTimeMillis is greater then TIMESTAMP if (System.currentTimeMillis() > Long.parseLong(sid[1])) { logger.error("Authentication rejected for: {}", soeid); throw new NonceExpiredException("Authentication token is expired"); } // saving decoded SOEID in a REQUEST to reuse it by obtainUsername() request.setAttribute("SSO_USER_SOEID", soeid); return super.attemptAuthentication(request, response); } @Override protected String obtainPassword(final HttpServletRequest request) { return DEFAULT_AUTH_PASSWORD; } @Override protected String obtainUsername(final HttpServletRequest request) { //SM_USER is coming from SSO after login return (String) request.getAttribute("SM_USER"); } private String[] decodeSID(final HttpServletRequest request) { .............add SSO server decode strtegy } }
You may say above sample was not my case, what happens we have SSO setup in the proxy server as below?
![](http://dl2.iteye.com/upload/attachment/0118/8615/2525dae2-ee24-3ee0-98fe-e58799aa33b7.jpg)
only difference is in the login entry filter, we redirect to the web app authentication filter("/authenticate") as it's pre-logged in
public class SSOLoginHandler extends LoginUrlAuthenticationEntryPoint { private final Logger logger = LoggerFactory.getLogger(SSOLoginHandler.class); private String authProcessingURL; @Override public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authenticationException) throws IOException, ServletException { logger.debug("Preparing redirectiion to SSO PROXY..."); new DefaultRedirectStrategy().sendRedirect(request, response, "/authenticate"); } }