Announcement Announcement Module
No announcement yet.
Hacks using Programmatic Security for a SpringMVC application Page Title Module
Move Remove Collapse
Conversation Detail Module
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hacks using Programmatic Security for a SpringMVC application

    I have implemented programmatic security by reading through the docs and the forums when I ran into issues.

    Everything seems to be working fine but one thing is still bothering me.

    In my controller, I am using the following calls.

    Authentication auth = new AppAuthentication(accessToken);
    SecurityContextHolder.getContext().setAuthenticati on(auth);

    //AppAuthentication is my custom implementation of the Authentication Interface.

    If I do not set the Authentication Context for the current user in the HTTP session, the context is not available to me on subsequent calls.

    HttpSession session = request.getSession();
    session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());

    Is this the intended approach or more of a hack? What would be preferred approach in this case?

  • #2
    What exactly are you trying to achieve with your custom implementation? If you tell us some more about your overall goals we can recommend an approach.


    • #3
      The authentication provider is an external system for which I am using OAUTH to authenticate & authorize. I do all of the OAUTH communication in my controller. Once the user is successfully authenticated & authorized externally, I need to make Spring aware of the authenticated user along with any roles I define so I can use the spring security model through out the application.


      • #4
        What does your security configuration look like? If you invoke SecurityContextHolder.getContext().setAuthenticati on(...) on a URL that is not viewed by Spring Security, then it does not get persisted to session automatically. For example, if you are using <http security="none"> (Spring Security 3.2) or <intercept-url filters="none"> (Spring Security 3.1) it will not be persisted by the SecurityContextPersistenceFilter since Spring Security is disabled for that URL. Instead, you should map the URL you are performing authentication to "permitAll" (when use-expressions="true") or "ROLE_ANONYMOUS" (when use-expressions="false").


        • #5
          Ok, now this is beginning to make some sense. As i was thinking the same thing from the containers perspective.

          So for the URL (in this case /signup) that the user submits the data to, I have security set to <security:http pattern="/signup" security="none" />
          My thought of having it setup as none was because i thought the container would apply security to that URL in effect defecting the purpose of the URL. But now i see how the option can be defined to allow a permit all on that.
          So if i change to - <security:intercept-url pattern="/twitterSignup" access="permitAll" /> you think i do not need to use the lines
          HttpSession session = request.getSession();
          session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());


          • #6
            Originally posted by boomkap View Post
            So if i change to - <security:intercept-url pattern="/twitterSignup" access="permitAll" /> you think i do not need to use the lines
            HttpSession session = request.getSession();
            session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext());
            Correct. It sounds like you will have this setup after this change, but if you want more details this presentation discusses how to do signup in Spring Security. Alternatively, you can refer to the SecureMail application that the presentation uses.


            • #7
              That worked as expected and makes a lot more sense now.

              The next thing on my todo is to put in the remember me functionality. I read the docs - on that I do not quite understand all the plumbing required to get it to work in the case when authentication is programmatic.

              The in-built TokenBasedRememberMeServices should work for what I am trying to get done. The docs do not mention what interface the UserDetailsService needs to implement.

              So if I were to use the in built TokenBasedRememberMeServices, then the only thing I need to implement my version of the UserDetailsService?


              • #8
                You would also need to ensure you call RememberMeServices#loginSuccess and RememberMeServices#loginFail in your controller


                • #9
                  so do I need to implement the same interface as defined in this class memberme.TokenBasedRememberMeServices ?


                  • #10
                    You need to use the interface as is done in the UsernamePasswordAuthenticationFilter (i.e. invoke the two previously mentioned methods). I'd give the reference a read, see how Remember Me works in the UsernamePasswordAuthenticationFilter, and then translate it to your code.


                    • #11
                      Glad to give it a read. Which resource should I be reading? I need to understand the configuration as well as the implementation classes.

                      This document does not really help me. Is there another resource you are referring to?


                      • #12
                        Check out the source code for AbstractAuthenticationProcessingFilter, especially the methods successfulAuthentication and unsuccessfulAuthentication, you will see how they call rememberMeServices.


                        • #13
                          I did check out the source code. Let me see if I understand the workflow.

                          Lets assume I want to use the default TokenBasedRememberMe service. In my controller, I need to first initialize the TokenBasedRememberMe object. After I authenticate the user programmatically, I call rememberMeServices.loginSuccess(request, response, authResult) so it can drop the cookie in the response object. Simple enough so far.

                          Now on subsequent requests the TokenBasedRememberMeServices intercepts the call to check for the cookie and look for the identifiable user. If the user session is not located on the server, the TokenBasedRememberMeService needs to create a new session that represents the user. To do this, it needs to check whether the password for the user may have changed since the last visit. To do this it needs a UserDetailsService to compare the password with the password it had stored in the cookie.
                          If there is a match, it creates a session object and everything proceeds as normal.
                          If there is no match, it sends the user to the Login form so the process can start again.

                          From a containers perspective, all I need to do is tell it that I need to use a RememberMe service, define which one (in this case TokenBasedRememberMeServices) and the UserDetailsService that goes along with this.

                          Is this the general flow, or am I missing anything?


                          • #14
                            That's broadly correct, at least in the context of the TokenBasedRememberMeServices. Personally I would recommend using the PersistentTokenBasedRememberMeServices as it's more secure but the choice is yours.


                            • #15
                              Thanks a lot. Will try and implement this and see how it goes. .