Skip to content

Allow override AbstractPreAuthenticatedProcessingFilter#requiresAuthentication #5928

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

ttddyy
Copy link
Contributor

@ttddyy ttddyy commented Oct 8, 2018

Hi,

I'd like to add more precheck logic on AbstractPreAuthenticatedProcessingFilter#requiresAuthentication. (Currently, it is a private method)
Similar class AbstractAuthenticationProcessingFilter has requiresAuthentication as a protected method.

Making the method protected allows sub-classes to extend the precondition check.

Thanks,

@rwinch
Copy link
Member

rwinch commented Oct 10, 2018

Thanks for the suggestion. Please change this to use a RequestMatcher with the default implementation being private and using the same existing logic. This is preferable since Spring prefers composition to inheritance.

@ttddyy ttddyy force-pushed the preauthfilter-loosen-requiresAuth-scope branch from 94cf631 to d810dbb Compare October 10, 2018 19:38
@ttddyy
Copy link
Contributor Author

ttddyy commented Oct 10, 2018

@rwinch

Updated the PR to use RequestMatcher in AbstractPreAuthenticatedProcessingFilter
Thanks,

Copy link
Member

@rwinch rwinch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fast turnaround. See my comments for areas of concern.

@@ -194,6 +203,11 @@ private void doAuthenticate(HttpServletRequest request, HttpServletResponse resp
}

private boolean requiresAuthentication(HttpServletRequest request) {

if (!authenticationRequestMatcher.matches(request)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm interested in discussing this approach where it augments the existing logic for when authentication is required vs being the entire logic (i.e. the default implementation of RequestMatcher copies the logic from this method). What are your thoughts on each approach?

My concern about augmenting the existing logic is that there is no way to change the existing logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean performing request matcher check in requiresAuthentication() method vs performing the check in doFilter(), so that entire logic of this filter may be skipped if request doesn't match?

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
    throws IOException, ServletException {
    
    if(!requiresAuthenticationRequestMatcher.matches(request)){
      chain.doFilter(request, response);
      return;
    }
    
    // existing logic from here
    
    if (!requiresAuthentication(request, response)) {
      chain.doFilter(request, response);
      return;
    }
    ...
}

Currently, requiresAuthentication() method on this class AbstractPreAuthenticatedProcessingFilter (APAPF) is private, so where to put the request-matcher check doesn't really affect any other existing sub classes. So, behavior-wise it is same.

The similar class AbstractAuthenticationProcessingFilter(AAPF), the request-matcher check is in requiresAuthentication() which is a protected method.

So, to align the implementation with AAPF, then request-matcher check is in requiresAuthentication().
If we consider request-matcher check is the first-check even before requiresAuthentication(), then the check can go into doFilter()(shown in above snippet), and maybe update the AAPF as well (updating AAPF will be a behavioral change).

My preference is put the request-matcher check in requiresAuthentication() as in current PR which aligns with AAPF, then also make requiresAuthentication() protected, so that sub-class can modify the behavior, even it is inheritance. (Yes, I know spring is for composition, but since this is an abstract class which is meant to be inherited and may be overridden.)

My concern about augmenting the existing logic is that there is no way to change the existing logic.

Currently the method is private, adding all-match request-matcher should have no impact to existing logic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that it won't have an impact on users. My concern is that as it is written now, a user cannot ignore the existing logic. For example, what if they don't want it to require authentication if the current user is null when requesting the URL /foo/bar? This would not be possible as implemented in this PR. So my suggestion was to move all of this to the default RequestMatcher implementation so that users can customize anything they want.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, logic can be moved to RequestMatcher implementation.

private class PreAuthenticatedProcessingRequestMatcher implements RequestMatcher {

  @Override
  public boolean matches(HttpServletRequest request) {

    Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();

    if (currentUser == null) {
      return true;
    }

    if (!checkForPrincipalChanges) {
      return false;
    }

    if (!principalChanged(request, currentUser)) {
      return false;
    }

    logger.debug("Pre-authenticated principal has changed and will be reauthenticated");

    if (invalidateSessionOnPrincipalChange) {
      SecurityContextHolder.clearContext();

      HttpSession session = request.getSession(false);

      if (session != null) {
        logger.debug("Invalidating existing session");
        session.invalidate();
        request.getSession();
      }
    }

    return true;
  }

}

and caller side is:

private boolean requiresAuthentication(HttpServletRequest request) {
  return authenticationRequestMatcher.matches(request);
}

Though, in the matcher logic, there are still references:
checkForPrincipalChanges, invalidateSessionOnPrincipalChange variables, and principalChanged method.

two variables can be passed to matcher, and principalChanged method can be also moved to matcher (though it is currently a protected method).

Is this what you mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Since the default implementation is internal it would still be able to refer to the member variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, updated the PR.
Moved the existing auth check logic into the new request matcher.

@ttddyy ttddyy force-pushed the preauthfilter-loosen-requiresAuth-scope branch from d810dbb to a7d9dba Compare October 17, 2018 18:03
@rwinch
Copy link
Member

rwinch commented Oct 17, 2018

Thanks for the updates. I have provided additional feedback.

Moved the existing auth check logic to the matcher.

Issue: spring-projectsgh-5928
@ttddyy ttddyy force-pushed the preauthfilter-loosen-requiresAuth-scope branch from a7d9dba to 4cc4f35 Compare October 17, 2018 21:28
@ttddyy
Copy link
Contributor Author

ttddyy commented Oct 17, 2018

Updated the PR and reflected the feedbacks

@rwinch rwinch added this to the 5.2.0.M1 milestone Oct 17, 2018
@rwinch rwinch self-assigned this Oct 17, 2018
@rwinch rwinch added in: web An issue in web modules (web, webmvc) type: enhancement A general enhancement labels Oct 17, 2018
@rwinch
Copy link
Member

rwinch commented Oct 17, 2018

Thanks for the fast turnaround! Looks good to me. I'm going to wait for the build to complete before merging into master

@rwinch rwinch modified the milestones: 5.2.0.M1, 5.2.0.M2 Jan 16, 2019
@jgrandja jgrandja modified the milestones: 5.2.0.M2, 5.2.0.RC1 Apr 15, 2019
@eleftherias eleftherias modified the milestones: 5.2.0.M3, 5.2.0.RC1 Jun 14, 2019
@rwinch rwinch removed their assignment Jul 29, 2019
@jzheaux jzheaux modified the milestones: 5.2.0.M4, 5.2.0.RC1 Aug 5, 2019
@jzheaux jzheaux modified the milestones: 5.2.0.RC1, 5.2.0 Sep 5, 2019
@rwinch rwinch modified the milestones: 5.2.0, 5.2.x Sep 30, 2019
@eleftherias eleftherias merged commit 62c7de0 into spring-projects:master Oct 22, 2019
@eleftherias eleftherias self-assigned this Oct 22, 2019
@eleftherias
Copy link
Contributor

Thanks for the PR @ttddyy! This is now merged into master.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc) type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants