Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    How TO relogin with SpringSecurity 3.0

    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.

    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>
    Last edited by hanishi; 11 Feb 2010, 06:49.

    #2
    Thanks for posting all of that.

    That seemed to require a great deal of Spring configuration. Is there anything we could do to make this simpler in Spring?

    Comment


      #3
      The only problem I think there is( and may be not so problem)
      is the LoginUrlAuthenticationEntryPoint that is used with UsernamePasswordAuthenticationFilter for the form login, do check for a valid url redirectable path and if it is not found, it will respond with a text that says "your session is invalid." So this needs to be replaced with a class that responds with the "marker" contents.
      Same principle for BiztrackConcurrentSessionFilter. You need to implement one of your own to pickup session timeout notification emitted by server.
      Filters provided by the SpringSecurity which are the ones very easy configurable basically redirects request in the failure of authentication and not meant to be used for Ajax login,I guess.

      Other thing I posted above can be much simpler. SpringSecurity configuration cannot be any simpler as this custom filter is introduced.(SpringSecurity's automatically set up the LoginUrlAuthenticationEntryPoint as its default AuthenticationEntryPoint for the form login)

      And use something like the following to retrieve the principal. (There is actually no need to extend IDACall, even though the document says so, if what you are trying to do is get the principal of the user)
      Code:
      Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      
      if (principal instanceof UserDetails) {
        String username = ((UserDetails)principal).getUsername();
      } else {
        String username = principal.toString();
      }
      and some code that triggers first relogin mechanism.

      Code:
      public class TabSetBuilder {
          public static void buildTabSetOn(final Canvas canvas){
              RPCRequest request=new RPCRequest();
              request.setActionURL("/biztrack/sc/UserDetailsServlet");
              request.setHttpMethod("GET");
              request.setShowPrompt(false);
              RPCManager.sendRequest(request,new RPCCallback(){
                
                  @Override
                  public void execute(RPCResponse rpcResponse, Object o, RPCRequest rpcRequest) {
                      TabSet mainTabSet=new TabSet();
                      mainTabSet.setTabBarPosition(Side.TOP);
                      mainTabSet.setTabBarAlign(Side.LEFT);
                      mainTabSet.setWidth100();
                      mainTabSet.setHeight100();
                      mainTabSet.addTabSelectedHandler(new TabSelectedHandler(){
      
                          @Override
                          public void onTabSelected(TabSelectedEvent tabSelectedEvent) {
                              Tab selectedTab=tabSelectedEvent.getTab();
                              String title=selectedTab.getTitle();
                              History.newItem(title,false);
                          }
                      });
                      Map<String,String> principal=rpcResponse.getAttributeAsMap("data");
                      String authority=principal.get("authority");
                      if(authority.equals("ROLE_ADMINISTRATOR")){
                          mainTabSet.addTab(createTab(new SomeCanvas.Factory()));
                      }else
                        ......
                        ......
                      canvas.addChild(mainTabSet);
                      canvas.draw();
                  }
              });
          }
      
          private static Tab createTab(PanelFactory factory){
              Canvas canvas=factory.create();
              Tab tab=new Tab(factory.getTitle(),factory.getIcon());
              tab.setPane(canvas);
              return tab;
          }
      }
      and the service. that provides the UserDetails. You also need to intercept request made to the URL of this servlet.
      Code:
      public class UserDetailsServlet extends HttpServlet {
      
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doGet(request,response);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              try{
                  RPCManager rpc=new RPCManager(request,response);
                  for(Iterator itr=rpc.getRequests().iterator();itr.hasNext();){
                      Object req=itr.next();
                      if(req instanceof RPCRequest){
                          Object principal= SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                          Account account=(Account)principal;
                          Map<String,String>attributes=new HashMap<String,String>();
                          attributes.put("username",account.getUsername());
                          attributes.put("authority",account.getAuthority());
                          attributes.put("firstName",account.getFirstName());
                          attributes.put("lastName",account.getLastName());
                          rpc.send(attributes);
                      }
                  }
              } catch (Exception e) {
                  throw new ServletException(e);
              }
          }
      }
      Above is just a simple example. There's better way I think.

      When User log in succeeds and relogin mechanisom re-request for the principal. User is already authenticated so the request made by the RPCManager in the code above succeeds and granted authority of the user just logged in becomes available to client side and it can start filling the canvas using the information returned.
      Secure your methods too.
      Last edited by hanishi; 20 Feb 2010, 05:39.

      Comment


        #4
        hanishi,
        Thanks for posting this. I think this sample is extremely useful for users wanting to incorporate SpringSecurity with SmartGWT. I'd like to include this sample in the SmartGWT distribution and perhaps even write a blog about it (ofcourse giving full credit to you). Do you grant permission to do this?

        Thanks,
        Sanjiv

        Comment


          #5
          Originally posted by sjivan
          hanishi,
          Thanks for posting this. I think this sample is extremely useful for users wanting to incorporate SpringSecurity with SmartGWT. I'd like to include this sample in the SmartGWT distribution and perhaps even write a blog about it (ofcourse giving full credit to you). Do you grant permission to do this?

          Thanks,
          Sanjiv
          No problem at all. Don't need any credit either. : ) It may not be the best solution and others might have come up with better ideas,but works for me at least.
          Relogin mechanism provided with the SmartGWT Pro/EE is remarkable and provides cleanest login mechanism that best matches this type of single entry point application I believe. It is definitely worth buying the license for what it gives you. It is my pleasure to help others who needs some tips and tricks to achieve their goals,as I am always helped by posts made by others other times. Great work,by the way, Mr.sjivan.

          Comment


            #6
            Thanks hanishi, your contribution is definitely appreciated. I perused the code and it looks good. If it makes sense, I'll make the appropriate modifications as I work through creating the sample.

            Sanjiv

            Edit : Can you shoot me an email at sanjiv dot jivan at gmail dot com with your full name
            Last edited by sjivan; 20 Feb 2010, 05:42.

            Comment


              #7
              sjivan,

              just want to ask about the state. Really hoped you can provide this as part of the S'GWT distribution...

              Please let us know...

              Ekki

              * GWT Rocks! * SmartGWT Rocks Even Harder! * SmartGWT PRO 2.1,
              GWT 2.0, Jetty 7.0.0, Eclipse 3.5.1, JRE 1.6.0_16 *
              For Evaluation only: MySQL 5.1.41, Connector/J 5.1.10

              *** www.EasternGraphics.com/X-4GPL ***

              Comment


                #8
                additions for BuiltInDS sample

                I was able to get the login working using the BuiltInDS sample with the following additions/customisations:

                web.xml
                Code:
                <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
                    version="2.4">
                
                    <!--
                      - Location of the XML file that defines the root application context
                      - Applied by ContextLoaderListener.
                      -->
                    <context-param>
                        <param-name>contextConfigLocation</param-name>
                        <param-value>
                            /WEB-INF/applicationContext-security.xml
                        </param-value>
                    </context-param>
                
                
                    <context-param>
                        <param-name>webAppRootKey</param-name>
                        <param-value>tutorial.root</param-value>
                    </context-param>
                     <listener>
                        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
                    </listener>
                
                    <!--
                      - Publishes events for session creation and destruction through the application
                      - context. Optional unless concurrent session control is being used.
                      -->
                    <listener>
                      <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
                    </listener>
                    <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>
                
                
                
                    <!-- Note: The servlets/filters referenced here are documented in the SDK javadoc -->
                
                    <!-- //>FileLoader -->
                    <!-- Dynamic Compression -->
                    <filter>
                        <filter-name>CompressionFilter</filter-name>
                        <filter-class>com.isomorphic.servlet.CompressionFilter</filter-class>
                    </filter>
                    <!-- CompressionFilter for dynamic compression -->
                    <filter-mapping>
                        <filter-name>CompressionFilter</filter-name>
                        <url-pattern>/*</url-pattern>
                    </filter-mapping>
                    <!-- //<FileLoader -->
                    
                    <!-- The IDACall servlet handles all Built-in DataSource operations -->
                    <servlet>
                        <servlet-name>IDACall</servlet-name>
                        <servlet-class>com.isomorphic.servlet.IDACall</servlet-class>
                    </servlet>
                
                    <!-- The DataSourceLoader servlet returns Javascript representations of the dataSources whose
                         ID's are passed to it - it is an alternative to using the <loadDS> JSP tag -->
                    <servlet>
                        <servlet-name>DataSourceLoader</servlet-name>
                        <servlet-class>com.isomorphic.servlet.DataSourceLoader</servlet-class>
                    </servlet>    
                
                    <!-- The FileDownload servlet downloads static files, like a webserver -->
                    <servlet>
                        <servlet-name>FileDownload</servlet-name>
                        <servlet-class>com.isomorphic.servlet.FileDownload</servlet-class>
                    </servlet>
                
                	<!-- ISC init: initializes ISC framework -->
                    <servlet>
                        <servlet-name>Init</servlet-name>
                        <servlet-class>com.isomorphic.base.Init</servlet-class>
                        <load-on-startup>1</load-on-startup>
                    </servlet>
                	  
                    <servlet>
                        <servlet-name>HttpProxy</servlet-name>
                        <servlet-class>com.isomorphic.servlet.HttpProxyServlet</servlet-class>
                    </servlet>
                
                    <!-- The PreCache servlet initializes when the servlet engine starts up and pre-loads 
                         data need for all client requests.  This is optional, and improves performance
                         of the first few page requests.  PreCache cannot be invoked by a browser, because
                         there is no "servlet-mapping" defined for it. -->
                    <servlet>
                        <servlet-name>PreCache</servlet-name>
                        <servlet-class>com.isomorphic.servlet.PreCache</servlet-class>
                        <load-on-startup>2</load-on-startup>
                    </servlet>
                
                    <!-- RPCManager uses this URL by default for Built-in DataSource operations -->
                    <servlet-mapping>
                        <servlet-name>IDACall</servlet-name>
                        <url-pattern>/builtinds/sc/IDACall/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- DataSourceLoader requests -->
                    <servlet-mapping>
                        <servlet-name>DataSourceLoader</servlet-name>
                        <url-pattern>/builtinds/sc/DataSourceLoader</url-pattern>
                    </servlet-mapping>
                
                
                    <servlet-mapping>
                        <servlet-name>HttpProxy</servlet-name>
                        <url-pattern>/builtinds/sc/HttpProxy/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- Use FileDownload servlet to download all static content that's part of the skin, such as
                         image files, so we can set Expires headers and other cache control directives.  In a
                         production deployment, you'd want to use a webserver such as Apache to do this.  
                    -->
                    <servlet-mapping>
                      <servlet-name>FileDownload</servlet-name>
                      <url-pattern>/builtinds/sc/skins/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- serve ISC modules compressed, with expires headers -->
                    <servlet-mapping>
                        <servlet-name>FileDownload</servlet-name>
                        <url-pattern>/builtinds/sc/system/modules/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- serve ISC development modules compressed, with expires headers -->
                    <servlet-mapping>
                        <servlet-name>FileDownload</servlet-name>
                        <url-pattern>/builtinds/sc/system/development/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- server skin assets with expires headers -->
                    <servlet-mapping>
                        <servlet-name>FileDownload</servlet-name>
                        <url-pattern>/builtinds/sc/system/reference/skin/*</url-pattern>
                    </servlet-mapping>
                
                    <!-- General config -->
                    <session-config>
                        <session-timeout>30</session-timeout>
                    </session-config>
                
                    <jsp-config>
                        <!-- Isomorphic JSP tags -->
                        <taglib>
                            <taglib-uri>isomorphic</taglib-uri> 
                            <taglib-location>/WEB-INF/iscTaglib.xml</taglib-location> 
                        </taglib>
                    </jsp-config>
                
                
                </web-app>
                applicationContext-security.xml (put this in your web-inf dir)
                Code:
                <?xml version="1.0" encoding="UTF-8"?>
                
                <!--
                  - Sample namespace-based configuration
                  -
                  -->
                
                <beans:beans xmlns="http://www.springframework.org/schema/security"
                    xmlns:beans="http://www.springframework.org/schema/beans"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xmlns:security="http://www.springframework.org/schema/security"
                    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
                
                    <!-- 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="/builtinds/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>
                
                    <beans:bean id="formLoginFilter"
                          class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
                        <beans:property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy"/>
                        <beans:property name="authenticationManager" ref="authenticationManager"/>
                        <beans:property name="authenticationSuccessHandler">
                            <beans:bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationSuccessHandler"/>
                        </beans:property>
                        <beans:property name="authenticationFailureHandler">
                            <beans:bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationFailureHandler"/>
                        </beans:property>
                    </beans:bean>
                
                    <beans:bean id="authenticationEntryPoint"
                          class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackAuthenticationEntryPoint"/>
                
                    <beans:bean id="accessDeniedHandler"
                          class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
                        <beans:property name="errorPage" value="/accessDenied.htm"/>
                    </beans:bean>
                
                    <beans:bean id="concurrencyFilter" class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackConcurrentSessionFilter">
                        <beans:property name="sessionRegistry" ref="sessionRegistry"/>
                        <beans:property name="invalidSessionHandler">
                            <beans:bean class="jp.co.alibaba.biztrack.gwt.server.authentication.BiztrackInvalidSessionHandler"/>
                        </beans:property>
                    </beans:bean>
                
                    <beans:bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
                        <beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>
                        <beans:property name="maximumSessions" value="1"/>
                    </beans:bean>
                    
                    <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
                </beans:beans>
                Then delete the spring-2.0.8.jar and remove from the classpath. Create a lib directory in WEB-INF and copy the following jars (you will need to download Spring and Spring-Security 3.0), add to classpath
                Code:
                org.springframework.aop-3.0.2.RELEASE.jar
                org.springframework.asm-3.0.2.RELEASE.jar
                org.springframework.beans-3.0.2.RELEASE.jar
                org.springframework.context-3.0.2.RELEASE.jar
                org.springframework.core-3.0.2.RELEASE.jar
                org.springframework.expression-3.0.2.RELEASE.jar
                org.springframework.jdbc-3.0.2.RELEASE.jar
                org.springframework.transaction-3.0.2.RELEASE.jar
                org.springframework.web-3.0.2.RELEASE.jar
                spring-security-config-3.0.2.RELEASE.jar
                spring-security-core-3.0.2.RELEASE.jar
                spring-security-web-3.0.2.RELEASE.jar
                Put all the classes from the first post in this package:
                Code:
                jp.co.alibaba.biztrack.gwt.server.authentication

                Comment


                  #9
                  Thank you for your post :)
                  Yes you have to remove the spring libraries that comes with the SmartGWT distribution and replace it with the current release so it meets the requirements of the SpringSecurity 3.0

                  Since the SpringSecurity is widely used authentication mechanism, it would be great if the distribution provides out of box solution.

                  If you are using IE,this solution doesn't seem to work unless you make changes to the browser's security configuration.
                  seems like the markers returned won't trigger the call back methods and I think this is not specific to the solution above.
                  Last edited by hanishi; 11 Apr 2010, 23:57.

                  Comment


                    #10
                    deploying to tomcat

                    Hi Hanishi,

                    It works fine when run from Eclipse, however when I run "ant war" and deploy the war to tomcat, I get a 404 error after entering username/password in the login window for "/builtinds/j_spring_security_check".

                    Did you deploy it on tomcat and make any tomcat specific setting changes for this url?

                    Thanks
                    Kedaar

                    Comment


                      #11
                      Not that I'm aware of..no changes made.
                      If the dialog shows then the j_spring_security_check is working.
                      Is your servlet returning your UserDetails properly?

                      Comment


                        #12
                        fixed

                        Tomcat seems to require case specific URLs, so I changed the entry point class slightly as follows and now it works:
                        Code:
                        public class BuiltInDS implements EntryPoint {
                            private static final String CREDENTIALS_URL="/BuiltInDS/j_spring_security_check";

                        Comment


                          #13
                          Doesn't the SpringSecurity converts the requested URL path to lower case, before they are checked against url patterns that you set for the request interception?
                          I think it is merely a configuration issue of some either the SpringSecurity or the web.xml
                          Last edited by hanishi; 19 Apr 2010, 08:16.

                          Comment


                            #14
                            Great, thanks for this thread :-) It works brilliantly for me.
                            Since I couldn't really quickly find another authentication way that is (maybe now) out-of-the-box, I tried this, and works well.

                            Comment


                              #15
                              I am extending this example with an authentication against a Mysql table, using the standard JdbcDaoImpl of SpringSecurity.

                              It does not seem to work. Should it work if the applicationContext-security.xml file is updated? This is how that file looks, the rest is unchanged:

                              Code:
                              <beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd                         http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">  
                                <!-- 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="/generatedcode/sc/IDACall*" access="ROLE_USER,ROLE_SUPER_ADMINISTRATOR"/>  
                                  <security:access-denied-handler ref="accessDeniedHandler"/>  
                                  <security:session-management session-authentication-strategy-ref="sessionAuthenticationStrategy"/> 
                                </security:http>  
                                <!-- There are two authentication providers, simple user-service, and authentication against a MySQL Table. -->  
                                <security:authentication-manager alias="authenticationManager"> 
                                  <security:authentication-provider> 
                                    <security:user-service> 
                                      <security:user name="admin" authorities="ROLE_SUPER_ADMINISTRATOR" password="test"/> 
                                    </security:user-service> 
                                  </security:authentication-provider>  
                                  <!-- Login using `users` table to authenticate against. -->  
                                  <security:authentication-provider user-service-ref="myUserTable" /> 
                                </security:authentication-manager>  
                              
                                <beans:bean id="myUserTable" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl"> 
                                  <beans:property name="dataSource" ref="dataSource"/> 
                                </beans:bean>  
                                <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
                                  <beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
                                  <beans:property name="url" value="jdbc:mysql://localhost:3306"/>  
                                  <beans:property name="username" value="test"/>  
                                  <beans:property name="password" value="test"/> 
                                </beans:bean>  
                                
                              
                                <beans:bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
                                  <beans:property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy"/>  
                                  <beans:property name="authenticationManager" ref="authenticationManager"/>  
                                  <beans:property name="authenticationSuccessHandler"> 
                                    <beans:bean class="nl.sytematic.projects.Persons.server.security.SytematicAuthenticationSuccessHandler"/> 
                                  </beans:property>  
                                  <beans:property name="authenticationFailureHandler"> 
                                    <beans:bean class="nl.sytematic.projects.Persons.server.security.SytematicAuthenticationFailureHandler"/> 
                                  </beans:property> 
                                </beans:bean>  
                                <beans:bean id="authenticationEntryPoint" class="nl.sytematic.projects.Persons.server.security.SytematicAuthenticationEntryPoint"/>  
                                <beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"> 
                                  <beans:property name="errorPage" value="/accessDenied.htm"/> 
                                </beans:bean>  
                                <beans:bean id="concurrencyFilter" class="nl.sytematic.projects.Persons.server.security.SytematicConcurrentSessionFilter"> 
                                  <beans:property name="sessionRegistry" ref="sessionRegistry"/>  
                                  <beans:property name="invalidSessionHandler"> 
                                    <beans:bean class="nl.sytematic.projects.Persons.server.security.SytematicInvalidSessionHandler"/> 
                                  </beans:property> 
                                </beans:bean>  
                                <beans:bean id="sessionAuthenticationStrategy" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"> 
                                  <beans:constructor-arg name="sessionRegistry" ref="sessionRegistry"/>  
                                  <beans:property name="maximumSessions" value="1"/> 
                                </beans:bean>  
                                <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/> 
                              </beans:beans>
                              Do I need to add other stuff? I'm not seeing any errors, in fact this happens when pressing login button. (Of course there were some users in the database, I followed the standard implementation and its table-structure)

                              Code:
                              === 2010-08-18 11:52:21,250 [l0-3] INFO  RequestContext - URL: '/generatedcode/j_spring_security_check', User-Agent: 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8': Moz (Gecko) with Accept-Encoding header

                              Comment

                              Working...
                              X