Announcement Announcement Module
Collapse
No announcement yet.
extra authentication or force reauthentication important http url Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • extra authentication or force reauthentication important http url

    Want to force user to provide an extra factor of authentication one time token if they attempt to perform an important function.

    Something like this:

    The user is already authenticated via then standard mechanism, we want to force a re-authentication asking for a new AuthnRequest with a different AuthnContextClassRef upon attempt of authenticated users to get at an important url:
    Code:
    <intercept-url pattern="/importantEvent.htm" method="POST"  
    					   access="hasRole('AUTHENTICATION_TOKEN_ONETIME_OVERRIDE')"
    					   />
    Upon attempting this URL pattern in "POST" should trigger the re-authN based on the user would not having the Role, the system should instead of performing the standard requestLogin, it should do a requestTokenAuthentication.

    What type of filter should be used for this reauth N&Z event?
    It's a bit of a chicken and egg paradigm and it's unclear if
    Can we use the default <http namespace or create a dedicated one for this URL?
    Do we extend the existing <http authentication-manager AuthnProvider?
    Or does that all stay in place and we implement a permissionEvaluator or some sort of @PreAuthorization filter?
    What filter do we use and how do we re-call the AuthenticationManager requestLogin as requestTokenAuthentication?

    http://forum.springsource.org/showth...reauthenticate

    This question was asked and unanswered, I was looking for reauthentication, but with an enhanced mechanism.
    Last edited by kmacpher; Jul 1st, 2013, 09:51 AM.

  • #2
    extra info: Using spring-security-3.1 ...
    Is there reference how-to or recommendation for either (different) approach:

    1> AbstractSecurityInterceptor beforeInvocation RunAsManager replace the Authentication inside the SecurityContext with a different Authentication to a temporarily replace the Authentication object. Is this immutable? How is the re-Authentication in AuthenticationManager handled in the fact that the RunAsManager is temporarily substituted?

    It seems like this is only fancied for "key"="someotherpassword" -how this is expected to function is not clear. Is there any existing samples or reference implementations?

    2> SwitchUserFilter (su like to call and reAuth the user seems reasonable, but fairly new) - Does this filter fire in time for the authorization to have an effect?

    Comment


    • #3
      Trying another approach, as the RunAsManager doesn't seem to be able to force a redirect to the sso server for a new authentication, just modify the authentication on the fly and pass it through the chain.

      Looking at starting point of the http element using a different entry point reference.
      3>
      Code:
       
         <http name="tokenonly" pattern="/important.htm" entry-point-ref="reauthTokenOnly"  use-expressions="true">
      	<intercept-url pattern="/important.htm" method="POST"  
      					   access="hasRole('AUTH_TOKEN_ONETIME" />	
          </http>
          <http entry-point-ref= ... orginal .
      
      Except this just provides an HTTP Status 403 - Access is denied error, it uses the same security context which is good, but basically does a denial and doesn't do a redirect of the user's browser to the AuthN and issue a new request for token re-auth.
      We really can't kill the session cause we need to just pass the user back to the sso server for a additional factor of authentication.

      Going to try to use the Access Denied Handler based on the URL access to redirect back to SSO server for re-authN with Token.
      Last edited by kmacpher; Jul 1st, 2013, 09:51 AM.

      Comment


      • #4
        Any final thoughts on this design approach:

        <intercept-url pattern="/importantEvent.htm" method="POST" access="hasRole('AUTHENTICATION_TOKEN_ONETIME_OVER RIDE')" />

        Implement a custom GrantedAuthorityResolver
        add logic for reading the Security Context if (reAuthN) { GRANTED_AUTHORITIES.add('AUTHENTICATION_TOKEN_ONET IME_OVER RIDE');

        Let the standard voters fail if the reAuthN message if !GRANTED_AUTHORITIES.contains("1timetoken") aka: GA isn't present.

        QUESTION HERE: (Implement a custom Voter or AccessDeniedException to get URI access Authority violation details.
        Implement a standard voters to throw a standard "org.springframework.security.access.AccessDeniedE xception: Access is denied"

        Implement a custom ExceptionTranslationFilter to catch the specific thrown access denied details and re-call the RequestAuthn module (CAS/SAML/Siteminder etc) asking for the extra token login and upon successful authN get response redirected back to original target, all the aforementioned logic repeated this time GrantedAuthorityResolver sets the authority and the voters allow the access.

        Is this the best way to use Spring Security to handle this problem?

        Comment


        • #5
          Spring's default out of the box Security Interceptor only has a single exception of AccessDeniedException, the ExceptionTranslationFilter is "fixed and cannot be replaced with alternatives." Which one must assume means, can't be overridden and implement a CustomExceptionTranslationFilter.

          So implement a Custom AccessDenied .handle() but the AccessDeniedException is generic to either situation of a request being denied by the lack of AuthN or lack of Granted Authorities AuthZ.

          The flow for AuthN vs AuthZ is in the ExceptionTranslationFilter using if anon.

          Questions:

          1> write a custom voter to put error catch in request
          2> re-evaluate the ACL-ACE in a CustomAccessDeniedHandler and route the response flow back to sendStartAuthentication(request, response, chain, (AuthenticationException) exception);

          Any thoughts or experience with best way to handle this?

          Comment


          • #6
            We are using @PreAuthorize("@reAuth.isReAuthValid()") on controller and service methods - this is working fine, but there doesn't seem to be an obvious way from the DeniedAccessHandle to capture the method @PreAuthorize attribute from what caused this.

            It throws an exception, the generic, AccessDeniedException: Access is denied, nothing in the stack trace, reason code (**HINT**).

            I'm going to write code I think should work, but I'm trying to get the annotation on the controller method that caused the expression to throw this vote of -1. Here's my thoughts about how to get this. I'm beginner at Spring so forgive me. But I can't seem to figure out how to get the mapping for controller class, methods URL and annotations, I'm sure there some magical object in the context that will just do this (or not).

            At this point, I have the Request URL, context, how do I get back to the Controller class for this request and discover it's security attribute?

            ControllerClass
            Code:
             
                @RequestMapping(value="/importantEvent.htm", method = RequestMethod.POST)
                @PreAuthorize("@reAuthTokenValid.isReAuthTokenValid()")
                public String importantStep(
            Thought #1:

            In AccessDeniedHandler:
            Code:
             
            		BeanNameUrlHandlerMapping beanMapping = new BeanNameUrlHandlerMapping();
            		beanMapping.setApplicationContext(applicationContext);
            		beanMapping.initApplicationContext();
            		controllerClassMethod = beanMapping.getHandlerMap().get(getServletPath(request));
            		String reason controllerClass.getMethod(controllerClassMethod.getName()).getAnnotation(PreAuthorize).toString() ; 
            		if (reason.equals("@PreAuthorize("@reAuthTokenValid.isReAuthTokenValid()")") )
            			dispatch.redirect("to some other place");
            Obviously this will only work on controller classes, but what about service and delegate methods, that are protected?
            But I can't get the beanMapping to properly go, I could scan through all the beans in the applicationContext of type Controller, parse them myself and basically do what I think BeanNameUrlHandlerMapping should already do.

            Finally thought #2:
            Is there anyway to get back to the AbstractSecurityInterceptor
            obtainSecurityMetadataSource().getAttributes that caused this exception.

            Comment


            • #7
              Got it. Right Idea wrong class and don't forget context. Not happy with this, but it will have to do. Hopefully help somebody else if they need to do this.

              The security filters are firing in the applicationContext-spring-security.xml
              so put the bean in there, but the class is the RequestMappingHandlerMapping which gives a map to the key=RequestMappingInfo


              Code:
              	<beans:bean id="requestMappingHandlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
              Then your code will access the annotations, methods, mappings via your request object inside the accessdeniedhandler handle:

              Code:
                if (getMappingInfoFromRequestMappingHandler(request).getMethod().getAnnotation(PreAuthorize.class).value()=="@reAuthTokenValid.isReAuthTokenValid()") 
              redirect browser to reauth page; 
              ...
              
              
               public HandlerMethod  getMappingInfoFromRequestMappingHandler(HttpServletRequest request ){
                  	HandlerMethod  handlerMethodForThisRequest  = null; 
              		Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
              		Iterator<Map.Entry<RequestMappingInfo, HandlerMethod>> entries = handlerMethods.entrySet().iterator();
                      while (entries.hasNext()) {
                      	Map.Entry<RequestMappingInfo, HandlerMethod> entry = entries.next();
              
                      	if (entry.getKey().getMatchingCondition(request) !=null){
                          	logger.debug("RequestMappingInfo:"+ entry.getKey());
                          	logger.debug(entry.getValue().getClass()+"-(val): " +entry.getValue());
                          	
                      		return entry.getValue();
                      	}
                      }
                      return handlerMethodForThisRequest;
                  }

              Comment

              Working...
              X