Announcement

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

    #31
    I can try a test RPCManager send request and see how that works out.

    Does anyone have a working sample they could share as a download?

    Thanks,

    John Haigh

    Comment


      #32
      After reviewing the posts in this thread I have built a sample that includes a working LoginRequiredCallback for the builtinds sample.

      I am posting this sample here as a reference for anyone who may run into issues with getting LoginRequiredCallback to work.

      The default username/password is:

      Username: test
      Password: test

      I have tested this using GWT in Eclipse and with tomcat. Using ant you can run ant war against this sample and then deploy to tomcat.

      You can download this sample in 5 separate rar files:

      RAR Part 1: http://www.box.net/shared/s76ood5y43
      RAR Part 2: http://www.box.net/shared/25kip7vhmn
      RAR Part 3: http://www.box.net/shared/cm9olqc5jj
      RAR Part 4: http://www.box.net/shared/vznbz0r1ns
      RAR Part 5: http://www.box.net/shared/qi7bvcvzhe


      Thank You,

      John Haigh

      Comment


        #33
        I was wondering if someone could clarify how you got the principal. I have tried what I think you are doing below and I am not able to get the principal.

        I created a UserDetailsServlet and added the following to web.xml
        Code:
        <servlet>
               <servlet-name>userdetailsservlet</servlet-name>
               <servlet-class>jp.co.alibaba.biztrack.gwt.server.authentication.UserDetailsServlet</servlet-class>
           </servlet>
        
               <servlet-mapping>
               <servlet-name>userdetailsservlet</servlet-name>
               <url-pattern>/showcase/sc/UserDetails</url-pattern>
           </servlet-mapping>
        On the client I am using the following to get the principal through a RPCRequest:

        Code:
        RPCRequest request=new RPCRequest();
               request.setActionURL("/showcase/sc/UserDetails");
               request.setHttpMethod("GET");
               request.setShowPrompt(false);
        
               RPCManager.sendRequest(request,new RPCCallback()
               {
                       @Override
                   public void execute(RPCResponse rpcResponse, Object o,
        RPCRequest rpcRequest)
                   {
                               GWT.log("in execute");
                       Map<String,String>
        principal=rpcResponse.getAttributeAsMap("data");
                       Username = principal.get("username");
                       GWT.log("Username " + Username);
                   }
               });
        The part from the explanation below that is not clear is how did you intercept the request made to the URL of this servlet "intercept request made to the URL of this servlet."?

        Any help is greatly appreciated as I am have struggling to figure this out by re reading Spring Security documentation.

        Thank You,

        John Haigh

        Originally posted by hanishi
        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.

        Comment


          #34
          So, how to extend this Spring Security to the case when you have an app in which a part of the site is public, and part is not?

          Since datasource communications all run through IDACall, so should we then make IDACall public in our <intercept-url >, and put requireRole="..." on everything we want to make private?

          Comment


            #35
            Use requiresAuthentication="true". See the docs for this property - you can make it the default via a setting in server.properties.

            Comment


              #36
              yeah, but that docs state:

              Code:
              Likewise, setting requiresAuthentication="false" does not automatically allow users to bypass 
              your authentication mechanism - you need to set up a URL that will accept DSRequests and process
              them similar to the default "IDACall" servlet, and which is not protected by the authentication system. 
              
              See Deploying Smart GWT for details on the IDACall servlet.
              I know how to make an extension of IDACall, and all that, in fact I did this. But how to make a part of my system PUBLIC now, since currently my SecureIDACall is protected by an intercept-url filter from SpringSecurity.

              Should I then make the SecureIDACall public in SpringSecurity?

              so how to do:
              Code:
              you need to set up a URL that will accept DSRequests and process them similar to the default 
              "IDACall" servlet, and which is not protected by the authentication system.
              on a site that also has a public part? Then we need 2 instances of IDACall? how to do such a thing?

              Comment


                #37
                If you're using an authentication framework that is URL-based and is going to block access to IDACall before any of your application logic or SmartGWT server logic runs, then yes, in this instance you want to create separate a public/unprotected and private/protected registrations of the IDACall servlet, and use the public/unprotected version when you know the user is not logged in.

                You can do this via setting the dataURL on a DSRequest dynamically.

                Just to emphasize for other readers, this is the *only* case in which you would want to have data operations going to different URLs. In all other cases, all data operations need to go to the same URL to enable queuing of different operation types - see the QuickStart Guide chapter on the Server Framework, specifically the section of Queuing, to understand why.

                Comment


                  #38
                  Great, thanks for the info, that was really valuable. In my case there reaaly are two realms, a public portal and a private business app. This sounds like the neatest solution.

                  Comment


                    #39
                    Hi guys,

                    I had a slightly different requirement so i ended up doing a slightly different approach. It might prove useful to someone so i'll explain it. It's way simpler than the original approach.

                    I already have a "static" spring security setup, i.e. with form-login and a normal login.jsp forwarded to, configured in a form-login as such:

                    Code:
                    <form-login login-page="/security/login.jsp" authentication-failure-url="/security/login.jsp?login_error=1"
                                        authentication-failure-handler-ref="exceptionTranslationHandler"
                                        authentication-success-handler-ref="nubaAuthenticationSuccessHandler"
                                        default-target-url="/Nuba.html"/>
                    I have a normal "userdetailsservice" that i use to authenticate from my database and put custom stuff my application needs in the securitycontext. It's configured as such:
                    Code:
                    <authentication-manager alias="authenticationManager">
                            <authentication-provider user-service-ref="userDetailService">
                                <password-encoder ref="passwordManager"/>
                            </authentication-provider>
                        </authentication-manager>
                    The need i here have is the ability to send back marker snippets in the case of session timeout, unsuccessful login and successful login when it's performed from smartgwt, and do the "normal" login procedure when new users want to enter the site.

                    1. session timeout
                    Easy. Since spring security forward to the login.jsp in all cases, i just entered the "authentication required"-snippet to the top of my login.jsp. It's ignored if not evaluated by the RPCHandler.

                    2. login unsuccessful
                    See above, same thing.

                    3. login successful
                    Here i need to know whether it's a login from the login.jsp, in which case i want to forward to the main html as in my "old" spring security setup, or just return the snippet.

                    I therefor coded a class extension to the Spring class "SimpleUrlAuthenticationSuccessHandler" that checks whether the original URL contained the "relogin" parameter. If it does, i'll return the snippet. If it doesn't i'll just call the superclass which will run the usual URL-forwarding mechanism.

                    I then make sure that the login attempts from the login popup window include the "relogin=1" parameter in the credentials URL (as per the original example in this thread) so that the server knows that it came from my app.

                    This seems to work fine, but if anybody sees anything i've forgotten, please let me know.

                    code for my class:
                    Code:
                    public class NubaAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
                    
                        private static final Logger LOG = LoggerFactory.getLogger(NubaAuthenticationSuccessHandler.class);
                    
                        private static final String reloginParameter = "relogin";
                    
                        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>";
                    
                    
                        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    
                    
                            if(request.getParameter(reloginParameter)!=null){
                                if(LOG.isDebugEnabled()){
                                    LOG.debug("responded with SUCCESS_MARKER");
                                }
                                PrintWriter writer=response.getWriter();
                                writer.print(SUCCESS_MARKER);
                                response.flushBuffer();    
                            }else{
                                handle(request,response,authentication);
                            }
                        }
                    }

                    Comment


                      #40
                      I am just starting with Spring Security 3.0.5; and would like to integrate it with SmartClient; generally speaking I am searching for SmartClient community members who have already done that; and have had experiences with it ...

                      Since this thread seems to address this topic, I would like to ask: Is there already a consolidated and proven "SmartClient + Spring Security 3.0.5" integration solution available ? A straightforward solution which is described in a recipe-similar manner for other SmartClient community members ?

                      Comment


                        #41
                        I think the answer is no, although the first post of this topic will get you pretty far. I was able to use info from this topic to integrate with SmartGWT.

                        Comment


                          #42
                          Hello Systematic !

                          Please let me ask You: Would You be willing to make Your "SmartGWT - Spring Security" available as a download ?


                          Cheers and Tschüss

                          Kai

                          Comment


                            #43
                            Why I got -90 value for response.getStatus() when login success? Thanks a lot.

                            Comment


                              #44
                              I have met exactly the same problem here now! Any help is appreciated!!

                              Originally posted by haighis
                              I was wondering if someone could clarify how you got the principal. I have tried what I think you are doing below and I am not able to get the principal.

                              I created a UserDetailsServlet and added the following to web.xml
                              Code:
                              <servlet>
                                     <servlet-name>userdetailsservlet</servlet-name>
                                     <servlet-class>jp.co.alibaba.biztrack.gwt.server.authentication.UserDetailsServlet</servlet-class>
                                 </servlet>
                              
                                     <servlet-mapping>
                                     <servlet-name>userdetailsservlet</servlet-name>
                                     <url-pattern>/showcase/sc/UserDetails</url-pattern>
                                 </servlet-mapping>
                              On the client I am using the following to get the principal through a RPCRequest:

                              Code:
                              RPCRequest request=new RPCRequest();
                                     request.setActionURL("/showcase/sc/UserDetails");
                                     request.setHttpMethod("GET");
                                     request.setShowPrompt(false);
                              
                                     RPCManager.sendRequest(request,new RPCCallback()
                                     {
                                             @Override
                                         public void execute(RPCResponse rpcResponse, Object o,
                              RPCRequest rpcRequest)
                                         {
                                                     GWT.log("in execute");
                                             Map<String,String>
                              principal=rpcResponse.getAttributeAsMap("data");
                                             Username = principal.get("username");
                                             GWT.log("Username " + Username);
                                         }
                                     });
                              The part from the explanation below that is not clear is how did you intercept the request made to the URL of this servlet "intercept request made to the URL of this servlet."?

                              Any help is greatly appreciated as I am have struggling to figure this out by re reading Spring Security documentation.

                              Thank You,

                              John Haigh

                              Comment


                                #45
                                Can anyone tell me what for should i

                                configure your authentication system to send back the loginSuccessMarker as part of a successful login response
                                as it's stated here?

                                To get into

                                Code:
                                if (response.getStatus() == RPCResponse.STATUS_SUCCESS)
                                                    {
                                                     
                                                        RPCManager.resendTransaction();
                                                        loginWindow.hide();
                                                    }
                                ?

                                If loginSuccessMarker is for this pupropse - then i don't understand why i get RPCResponse.STATUS_SUCCESS on login WITHOUT implementing any custom logic to inject loginSuccessMarker.

                                I use standalone login page (with loginRequiredMarker) + spring security + RPC login from DynamicForm. And everything seems to work fine without loginSuccessMarker at all.
                                Last edited by vostapenko; 5 Sep 2012, 18:41.

                                Comment

                                Working...
                                X