Skip to content

Relax final method implementations on AbstractRememberMeServices #12145

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

Closed
okohub opened this issue Nov 7, 2022 · 12 comments
Closed

Relax final method implementations on AbstractRememberMeServices #12145

okohub opened this issue Nov 7, 2022 · 12 comments
Assignees
Labels
in: web An issue in web modules (web, webmvc) type: enhancement A general enhancement
Milestone

Comments

@okohub
Copy link
Contributor

okohub commented Nov 7, 2022

Expected Behavior

AbstractRememberMeServices implemented RememberMeServices methods with final modifier. This actually blocks overriding these methods. We can relax strictness on method implementations for further extensions.

Current Behavior

Any class that extends AbstractRememberMeServices can not override RememberMeServices methods.

Context

Is this behaviour necessary? I am not seeing any advantage for making these methods final, on an "abstract" service.

I can submit a PR for this.

@okohub okohub added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Nov 7, 2022
@sjohnr
Copy link
Contributor

sjohnr commented Nov 9, 2022

Thanks for reaching out @okohub! The preferred approach in Spring Security would be to start with a closed implementation and open up the API only when needed. I can't speak to the specific design considerations of AbstractRememberMeServices but it appears that there are many methods that can be overridden.

For example, loginFail cannot be, but cancelCookie and onLoginFail can be, which are the only two methods called within the final method. Can you provide more context behind your use case and a specific method you feel should not be final?

@sjohnr sjohnr self-assigned this Nov 9, 2022
@sjohnr sjohnr added status: waiting-for-feedback We need additional information before we can continue in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 9, 2022
@okohub
Copy link
Contributor Author

okohub commented Nov 10, 2022

@sjohnr hi,

We actually tried to create a new custom "RememberMeServices" implementation for some specific cases.

"AbstractRememberMeServices" is base class for "RememberMeServices" logic. Even with a new custom implementation, extending "AbstractRememberMeServices" class is inevitable, because main logic is embedded into abstract class.
(This is also another improvement context btw)

So here is the thing; hooking into "RememberMeServices" methods which are public interface methods, is prohibited because of final keyword on override.

Another point; if I want to delegate some methods to existing implementations (like PersistentTokenBasedRememberMeServices), I can't do this because of "AbstractRememberMeServices" limitations. Just implementing "RememberMeServices" is useless in this way, which I pointed above.

I think these public interface methods should not be implemented as final in abstract classes. This makes an ambiguity IMHO.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 10, 2022
@sjohnr
Copy link
Contributor

sjohnr commented Nov 10, 2022

Hi @okohub!

Just implementing "RememberMeServices" is useless in this way, which I pointed above.

Can you implement RememberMeServices and delegate to two implementations, both PersistentTokenBasedRememberMeServices and a custom one that extends AbstractRememberMeServices?

Another option would be to extend PersistentTokenBasedRememberMeServices instead. All of the methods it overrides from AbstractRememberMeServices can be overridden by your class. Could this work for your use case?

@sjohnr sjohnr added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Nov 10, 2022
@spring-projects-issues
Copy link

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Nov 17, 2022
@okohub
Copy link
Contributor Author

okohub commented Nov 23, 2022

@sjohnr Hi again! Sorry for late response.

Extending PersistentTokenBasedRememberMeServices is not solving our case. Actually we are making a transition to persistent repository implementation. So we need to support legacy token based implementation, but transform to persistent token result on actions. (login/logout etc.)

Relaxing final methods should help us a bit. We made a package name workaround to use some protected methods :) Let me share a bit of code:

package org.springframework.security.web.authentication.rememberme;

class MyService extends PersistentTokenBasedRememberMeServices {

...

  @Override
  protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
                                               HttpServletResponse response) {
     //if new cookie structure, go on                                          
    if (isPersistentRememberMeCookie(cookieTokens)) {
      return processPersistentAutoLoginCookie(cookieTokens[0]);
    }
    //if legacy, use legacy process to support user
    if (isNonPersistentRememberMeCookie(cookieTokens)) {
      return tokenBasedRememberMeServices.processAutoLoginCookie(cookieTokens, request, response);
    }
    throw new InvalidCookieException("Cookie does not resemble persistent or non persistent remember me cookie");
  }

...

}

We will get rid of these code blocks soon because transition is nearly completed. But I just wanted to find an improvement point to help other coders.

We can discuss more about, or you can close it if you don't see a significant point :)

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue labels Nov 23, 2022
@sjohnr
Copy link
Contributor

sjohnr commented Nov 23, 2022

Hi @okohub!

Relaxing final methods should help us a bit. We made a package name workaround to use some protected methods :)

I'm not sure I understand what you mean. In my testing, the protected methods of PersistentTokenBasedRememberMeServices (including processAutoLoginCookie) can be overridden by an extending class without the need to use a package-name workaround. It actually seems you are already using the suggestion I made above to extend PersistentTokenBasedRememberMeServices.

It even seems you're using delegation with TokenBasedRememberMeServices, similar to what I suggested. That would seem to confirm that it's possible to build everything you need without relaxing final methods on AbstractRememberMeServices. Am I misunderstanding your example code?

@sjohnr sjohnr added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Nov 23, 2022
@cgdsyilmaz
Copy link

cgdsyilmaz commented Nov 24, 2022

Hi @sjohnr!

I want to elaborate more on the package name workaround that @okohub mentioned. We are also trying to delegate our processAutoLoginCookie logic to TokenBasedRememberMeServices to support legacy cookies. However, doing the delegation in a class in an arbitrary package is impossible as the processAutoLoginCookie method of TokenBasedRememberMeServices is also protected.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 24, 2022
@sjohnr
Copy link
Contributor

sjohnr commented Dec 12, 2022

Hi @cgdsyilmaz!

We are also trying to delegate our processAutoLoginCookie logic to TokenBasedRememberMeServices to support legacy cookies. However, doing the delegation in a class in an arbitrary package is impossible as the processAutoLoginCookie method of TokenBasedRememberMeServices is also protected.

I think I see, thanks. It sounds like there are a couple of different improvements being suggested here. To clarify @cgdsyilmaz, are you and @okohub working on separate implementations, or is this all part of the same effort?

@okohub would you mind summarizing the improvements you're suggesting with specific class names and changes in each class, etc.? If there are multiple things here, we can open additional enhancements for items unrelated to the subject of this issue "Relax final method implementations on AbstractRememberMeServices".

@sjohnr sjohnr added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Dec 12, 2022
@cgdsyilmaz
Copy link

cgdsyilmaz commented Dec 13, 2022

Hi @sjohnr!

I think I see, thanks. It sounds like there are a couple of different improvements being suggested here. To clarify @cgdsyilmaz, are you and @okohub working on separate implementations, or is this all part of the same effort?

We are working on the same implementation, this is all part of the same effort.

We can think of two ways of solving our problem:

  • The first choice is relaxing the final method implementations on AbstractRememberMeServices which we still prefer. By doing so, we can extend the abstract class instead of extending concrete implementation (PersistentTokenBasedRememberMeServices).

  • The second one is to continue extending PersistentTokenBasedRememberMeServices as you have proposed. However, overriding autoLogin is still not possible because of the final implementation.

Also, for us to remove the package name workaround, relaxing the final method implementations or changing the access modifier of processAutoLoginCookie are needed.

You can select one solution and inform us of your selection.

@spring-projects-issues spring-projects-issues added the status: feedback-provided Feedback has been provided label Dec 13, 2022
@spring-projects-issues spring-projects-issues removed the status: waiting-for-feedback We need additional information before we can continue label Dec 13, 2022
@sjohnr
Copy link
Contributor

sjohnr commented Jan 10, 2023

@cgdsyilmaz sorry for the delay, and thanks for the great summary!

After reading the summary and understanding your challenge (thanks for providing all the details) I agree with your first choice and think it would make the most sense. I wanted to make sure there wasn't another way, but you've convinced me 😉! Since it's an either/or, let's stick with your first suggestion and not open additional issues.

Would you or @okohub be interested in submitting a PR for this?

@okohub
Copy link
Contributor Author

okohub commented Jan 10, 2023

@sjohnr Cool!

I will prepare a pull request for this. Thank you for your support.

@okohub
Copy link
Contributor Author

okohub commented Jan 12, 2023

I'm linking PR to this.

#12530

@sjohnr sjohnr assigned okohub and unassigned sjohnr Jan 13, 2023
okohub added a commit to okohub/spring-security that referenced this issue Jan 14, 2023
@sjohnr sjohnr closed this as completed in c77c76e Jan 17, 2023
@sjohnr sjohnr added this to the 6.1.0-M2 milestone Jan 17, 2023
@sjohnr sjohnr removed the status: feedback-provided Feedback has been provided label Jan 17, 2023
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

No branches or pull requests

4 participants