I've seen posts about how to handle smartGWT relogin with SpringSecurity.
Here is my way of doing it.
-create own classes that replaces some of generic spring security filters
so they can send markers that is evaluated by relogin mechanism.
-Wrap entire application with a relogin mechanism
(an implementation of relogin.js)
-intercept requests to IDACall*
Application is called Biztrack and here is how it is done.
Here is my way of doing it.
-create own classes that replaces some of generic spring security filters
so they can send markers that is evaluated by relogin mechanism.
-Wrap entire application with a relogin mechanism
(an implementation of relogin.js)
-intercept requests to IDACall*
Application is called Biztrack and here is how it is done.
Code:
public class Biztrack implements EntryPoint { private static final String CREDENTIALS_URL="/biztrack/j_spring_security_check"; private LoginWindow loginWindow; private LoginForm loginForm; private ApplicationPanel panel; public void onModuleLoad() { RPCManager.setLoginRequiredCallback(new LoginRequiredCallback(){ @Override public void loginRequired(int i, RPCRequest rpcRequest, RPCResponse rpcResponse) { if(loginWindow==null) loginWindow=new LoginWindow(); if(!(loginWindow.isVisible() && loginWindow.isDrawn())){ loginForm.clearValues(); loginForm.focusInItem("username"); } loginWindow.show(); loginWindow.bringToFront(); } }); panel=new ApplicationPanel(); panel.draw(); } public class LoginWindow extends Window { public LoginWindow(){ loginForm=new LoginForm(CREDENTIALS_URL); setShowModalMask(true); centerInPage(); setShowCloseButton(false); setShowMinimizeButton(false); setIsModal(true); setAutoSize(true); addItem(loginForm); } } private class LoginForm extends DynamicForm { private String credentialsURL; public LoginForm(String credentialsURL){ this.credentialsURL=credentialsURL; BlurbItem blurbItem=new BlurbItem("loginFailure"); blurbItem.setVisible(false); blurbItem.setColSpan(2); blurbItem.setDefaultValue("Invalid username or password"); blurbItem.setCellStyle("formCellError"); TextItem textItem=new TextItem("username"); textItem.setTitleOrientation(TitleOrientation.LEFT); textItem.addKeyPressHandler(new KeyPressHandler(){ @Override public void onKeyPress(KeyPressEvent keyPressEvent) { if(keyPressEvent.getKeyName().equals("Enter")){ focusInItem("password"); } } }); PasswordItem passwordItem=new PasswordItem("password"); passwordItem.setTitleOrientation(TitleOrientation.LEFT); passwordItem.addKeyPressHandler(new KeyPressHandler(){ @Override public void onKeyPress(KeyPressEvent keyPressEvent) { if(keyPressEvent.getKeyName().equals("Enter")){ doLogin(); } } }); ButtonItem buttonItem=new ButtonItem("Login"); buttonItem.addClickHandler(new ClickHandler(){ @Override public void onClick(ClickEvent clickEvent) { doLogin(); } }); setFields(textItem,passwordItem,buttonItem); } public void doLogin(){ RPCRequest request=new RPCRequest(); request.setContainsCredentials(true); request.setActionURL(credentialsURL); request.setUseSimpleHttp(true); request.setShowPrompt(false); Map<String,String> params=new HashMap<String,String>(); params.put("j_username",getValueAsString("username")); params.put("j_password",getValueAsString("password")); request.setParams(params); RPCManager.sendRequest(request,new RPCCallback(){ @Override public void execute(RPCResponse response, Object rawData, RPCRequest request) { clearValues(); if(response.getStatus()==RPCResponse.STATUS_SUCCESS){ hideItem("loginFailure"); RPCManager.resendTransaction(); loginWindow.hide(); }else if(response.getStatus()==RPCResponse.STATUS_LOGIN_INCORRECT){ showItem("loginFailure"); }else if(response.getStatus()==RPCResponse.STATUS_MAX_LOGIN_ATTEMPTS_EXCEEDED){ SC.warn("Max login attempts exceeded."); } focusInItem("username"); } }); } } }
Code:
public class BiztrackAuthenticationEntryPoint extends BiztrackMarkerResponseHandler implements AuthenticationEntryPoint { public BiztrackAuthenticationEntryPoint(){ setMarkerSnippet(LOGIN_REQUIRED_MARKER); } @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { handle(httpServletRequest,httpServletResponse,e); } }
Code:
public class BiztrackAuthenticationFailureHandler extends BiztrackMarkerResponseHandler implements AuthenticationFailureHandler { protected final Log logger = LogFactory.getLog(getClass()); public BiztrackAuthenticationFailureHandler(){ setMarkerSnippet(LOGIN_REQUIRED_MARKER); } @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { if(logger.isDebugEnabled()) logger.debug("responded with LOGIN_REQUIRED_MARKER"); handle(httpServletRequest,httpServletResponse,e); } }
Code:
public class BiztrackAuthenticationSuccessHandler extends BiztrackMarkerResponseHandler implements AuthenticationSuccessHandler { protected final Log logger = LogFactory.getLog(getClass()); public BiztrackAuthenticationSuccessHandler(){ setMarkerSnippet(SUCCESS_MARKER); } @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { if(logger.isDebugEnabled()) logger.debug("responded with SUCCESS_MARKER"); handle(httpServletRequest,httpServletResponse,authentication); } }
Code:
public class BiztrackConcurrentSessionFilter extends GenericFilterBean { private SessionRegistry sessionRegistry; private InvalidSessionHandler invalidSessionHandler; private LogoutHandler[] handlers = new LogoutHandler[] {new SecurityContextLogoutHandler()}; public void afterPropertiesSet(){ Assert.notNull(sessionRegistry,"SessionRegistry required"); Assert.notNull(invalidSessionHandler,"InvalidSessionHandler required"); } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)req; HttpServletResponse response=(HttpServletResponse)res; HttpSession session=request.getSession(false); if(session!=null){ SessionInformation info=sessionRegistry.getSessionInformation(session.getId()); if(info!=null){ if(info.isExpired()){ doLogout(request,response); if(invalidSessionHandler!=null) invalidSessionHandler.sessionInvalidated(request,response); else{ response.getWriter().print("This session has been expired (possibly due to multiple concurrent " + "logins being attempted as the same user)."); response.flushBuffer(); } return; }else{ info.refreshLastRequest(); } } } chain.doFilter(request,response); } private void doLogout(HttpServletRequest request, HttpServletResponse response) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); for(int i=0; i<handlers.length; i++) handlers[i].logout(request, response, auth); } public void setInvalidSessionHandler(InvalidSessionHandler invalidSessionHandler) { this.invalidSessionHandler = invalidSessionHandler; } public void setLogoutHandlers(LogoutHandler[] handlers) { Assert.notNull(handlers); this.handlers = handlers; } public void setSessionRegistry(SessionRegistry sessionRegistry) { this.sessionRegistry = sessionRegistry; } }
Code:
public class BiztrackInvalidSessionHandler extends BiztrackMarkerResponseHandler implements InvalidSessionHandler { protected final Log logger = LogFactory.getLog(getClass()); public BiztrackInvalidSessionHandler(){ setMarkerSnippet(LOGIN_REQUIRED_MARKER); } @Override public void sessionInvalidated(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if(logger.isDebugEnabled()) logger.debug("responded with LOGIN_REQUIRED_MARKER"); handle(request,response); } }
Code:
public abstract class BiztrackMarkerResponseHandler { protected static final String LOGIN_REQUIRED_MARKER="<SCRIPT>//'\"]]>>isc_loginRequired\n" + "//\n" + "// Embed this whole script block VERBATIM into your login page to enable\n" + "// SmartClient RPC relogin.\n" + "\n" + "while (!window.isc && document.domain.indexOf(\".\") != -1) {\n" + " try {\n" + "\t\n" + " if (parent.isc == null) {\n" + " document.domain = document.domain.replace(/.*?\\./, '');\n" + " continue;\n" + " } \n" + " break;\n" + " } catch (e) {\n" + " document.domain = document.domain.replace(/.*?\\./, '');\n" + " }\n" + "}\n" + "\n" + "var isc = top.isc ? top.isc : window.opener ? window.opener.isc : null;\n" + "if (isc) isc.RPCManager.delayCall(\"handleLoginRequired\", [window]);\n" + "</SCRIPT>"; protected final String SUCCESS_MARKER="<SCRIPT>//'\"]]>>isc_loginSuccess\n" + "//\n" + "// When doing relogin with a webserver-based authenticator, protect this page with it and\n" + "// target your login attempts at this page such that when the login succeeds, this page is\n" + "// returned.\n" + "//\n" + "// If you are integrating with a web service that returns a fault, paste this entire script\n" + "// block VERBATIM into the fault text.\n" + "\n" + "while (!window.isc && document.domain.indexOf(\".\") != -1) {\n" + " try {\n" + " if (parent.isc == null) {\n" + " document.domain = document.domain.replace(/.*?\\./, '');\n" + " continue;\n" + " } \n" + " break;\n" + " } catch (e) {\n" + " document.domain = document.domain.replace(/.*?\\./, '');\n" + " }\n" + "}\n" + "\n" + "var isc = top.isc ? top.isc : window.opener ? window.opener.isc : null;\n" + "if (isc) isc.RPCManager.delayCall(\"handleLoginSuccess\", [window]);\n" + "</SCRIPT>"; private String markerSnippet; protected void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { PrintWriter writer=httpServletResponse.getWriter(); writer.print(markerSnippet); httpServletResponse.flushBuffer(); } protected void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { PrintWriter writer=httpServletResponse.getWriter(); writer.print(markerSnippet); httpServletResponse.flushBuffer(); } protected void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException{ PrintWriter writer=httpServletResponse.getWriter(); writer.print(markerSnippet); httpServletResponse.flushBuffer(); } public String getMarkerSnippet() { return markerSnippet; } public void setMarkerSnippet(String markerSnippet) { this.markerSnippet = markerSnippet; } }
Code:
public interface InvalidSessionHandler { void sessionInvalidated(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException; }
Code:
spring configuration <!-- SpringSecurity --> <security:http entry-point-ref="authenticationEntryPoint"> <security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter"/> <security:custom-filter position="FORM_LOGIN_FILTER" ref="formLoginFilter"/> <security:anonymous enabled="false"/> <security:intercept-url pattern="/biztrack/sc/IDACall*" access="ROLE_USER"/> <security:access-denied-handler ref="accessDeniedHandler"/> <security:session-management session-authentication-strategy-ref="sessionAuthenticationStrategy"/> </security:http> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider> <security:user-service> <security:user name="test" authorities="ROLE_USER" password="test"/> <security:user name="guest" authorities="ROLE_USER" password="test"/> </security:user-service> </security:authentication-provider> </security:authentication-manager> <bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy"/> <property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationSuccessHandler"> <bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationSuccessHandler"/> </property> <property name="authenticationFailureHandler"> <bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationFailureHandler"/> </property> </bean> <bean id="authenticationEntryPoint" class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationEntryPoint"/> <bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> <property name="errorPage" value="/accessDenied.htm"/> </bean> <bean id="concurrencyFilter" class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackConcurrentSessionFilter"> <property name="sessionRegistry" ref="sessionRegistry"/> <property name="invalidSessionHandler"> <bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackInvalidSessionHandler"/> </property> </bean> <bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"> <constructor-arg name="sessionRegistry" ref="sessionRegistry"/> <property name="maximumSessions" value="1"/> </bean> <bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/> </beans>
Code:
web.xml <listener> <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> </listener> <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>
Comment