spring-projects / spring-projects/spring-security

SEC-2502: Overriding @PreAuthorize annotations on sub-interfaces does not behave as expected.

Open
#2,719 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: core type: bug type: jira
Dominant language
Java
Stars
9.6k
Forks
6.3k
Avg merge
2d 11h
Merged PRs (30d)
52

Description

Franklin Bristow (Migrated from SEC-2502) said:

I have a class hierarchy that includes a generic service implementation that all other service implementations extend. The generic service implementation has a corresponding generic service interface, and each of the other service implementations have corresponding interfaces that extend the generic interface. For example:

public interface GenericService<KeyType, ValueType> {
    // in general, anyone that's logged in should be able to read stuff.
    @PreAuthorize("isAuthenticated()")
    public ValueType read(KeyType s);
}
public class GenericServiceImpl<KeyType, ValueType> implements GenericService<KeyType, ValueType> {
    public ValueType read(KeyType s) {
        // implementation of read
    }
}
public interface WidgetService extends GenericService<Long, Widget> {
    // only administrators can read widgets:
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public Widget read(Long s);
}
public class WidgetServiceImpl extends GenericServiceImpl<Long, Widget> implements WidgetService {
    // GenericServiceImpl provides a default implementation of read.
}

What I expect to happen is that the @PreAuthorize annotation on the sub-interface will override the @PreAuthorize annotation on the super-interface.

The behavior of @PreAuthorize that I am receiving depends on the type of proxying that I am using (JDK-based vs Cglib-based).

By descending into the proxy with the debugger in eclipse, I can see that the instance of the method that the proxy is finding changes, depending on the type used on the reference of the injected class (i.e., using GenericService<Long, Widget> service vs WidgetService service).

I've attached a minimal test case that covers the problem that I am describing with three test cases that show what I expect to happen, with some comments that explain how changing the type of proxy used causes one, or the other to fail. One test case fails in all configurations.

I understand that I may be running into a language-level problem with Java and type erasure, but I think that what I'm trying to accomplish is not entirely unreasonable.

I think that this is related to two other issues: SEC-1234 and SEC-2144.

If the problem that I'm describing is a language-level problem, are there any other approaches that I can use to accomplish my expectations?

Thank you for developing Spring Security, it's saved me plenty of time, and the documentation is top-notch.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the attached minimal test case and its three tests, then inspect how @PreAuthorize metadata is resolved for JDK-based and Cglib-based proxies. Compare the behavior when the service is referenced through GenericService versus WidgetService; done means the sub-interface annotation behaves consistently with the stated expectations, or the limitation and supported approach are documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
authorization, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.