Skip to content

Integrate with SpringSecurity to consider authorization annotations on controller methods #1343

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

Open
amarocco opened this issue Jul 30, 2020 · 6 comments

Comments

@amarocco
Copy link

Looking at the documentation I would like to use RepresentationModelProcessor to:

Leverage cross cutting services like Spring Security to add, remove, or revise links based upon the current user’s context.

Could it be possible to provide a sample for such a case ?

I.e.: if I have a service.create() method secured with @PreAuthorize("isMember(#id)") I would like to use the same logic to add/hide link to representation accordingly.

if necessary I can provide a sample project

Thanks

@gregturn
Copy link
Contributor

gregturn commented Jul 30, 2020

Yes, you can use Spring Security to conditionalize links, but not necessarily every way you are imaging.

If you look at this section of Spring HATEOAS Examples, you'll notice a RepresentationModelProcessor being used to conditionally add links to a Spring Data REST application.

A) These conditional links are based upon the state of the Order. This is very much like what @odrotbohm has in his Spring RESTbucks demo app.
B) This concept works whether you're implementing a cross-domain RepresentationModelProcessor or an in-domain RepresentationModelAssembler.
C) This works for both Spring Data REST or Spring HATEOAS applications.

In the linked example, the links are applied based on the status of the Order. You could just as well grab the SecurityContextHolder and look at the current state of things to make a decision.

What's missing is the ability to peek look inside a @PreAuthorize(...) expression from another controller method when creating a link. If the method from which you're forming the link has different authorization rules than you one you're trying to link, there flat is NO WAY to run an extra security check and make a choice.

For example, if you were inside some employee-based method fetching data and wanted to form a link to a manager-based method, what do you do? If the manager-based method reveals manager-only data, you probably should NOT serve the link. But the current SecurityContextHolder won't know that, so you have no way to filter out that method using that approach.

I've chatted in the past with @rwinch about the chances of doing some dummy call through a proxy, kind of like Spring HATEOAS does now to glean method data, and trying to assess if access was "permitted". But that tactic has always been dodgy and not well defined. Simply put, Spring Security doesn't really an introspection API like that.

@rwinch
Copy link
Member

rwinch commented Jul 30, 2020

You can easily peek at a value if you are only concerned with @PreAuthorize and know what the arguments to the method are going to be. A snippet of this complete sample can be found below.

	@Autowired
	MethodSecurityInterceptor interceptor;

	@Autowired
	MessageService messages;

	@Test
	@WithMockUser
	public void peekMessageWhenUserThenAccessDenied() throws Throwable {
		MethodInvocation invocation = new SimpleProceedMethodInvocation(this.messages, this.messages.getClass().getMethod("getMessage"));

		assertThatCode(() -> this.interceptor.invoke(invocation)).isInstanceOf(AccessDeniedException.class);
	}

	@Test
	@WithMockUser(roles = "ADMIN")
	public void peekMessageWhenAdminTthenGranted() throws Throwable {
		MethodInvocation invocation = new SimpleProceedMethodInvocation(this.messages, this.messages.getClass().getMethod("getMessage"));

		assertThatCode(() -> this.interceptor.invoke(invocation)).doesNotThrowAnyException();
	}

	static class SimpleProceedMethodInvocation extends SimpleMethodInvocation {
		private final Object proceed;

		public SimpleProceedMethodInvocation(Object proceed, Object targetObject, Method method, Object... arguments) {
			super(targetObject, method, arguments);
			this.proceed = proceed;
		}

		public SimpleProceedMethodInvocation(Object targetObject, Method method, Object... arguments) {
			this(null, targetObject, method, arguments);
		}

		@Override
		public Object proceed() {
			return this.proceed;
		}
	}

What becomes more tricky is @PostAuthorize since it's expression may need to inspect the returned value. The only way to obtain the returned value is to invoke the actual method which you probably don't want to do (it may change the state of things) when trying to peek at authorization.

@odrotbohm
Copy link
Member

odrotbohm commented Aug 3, 2020

I'd like to explore options how we can enable that OOTB if Spring Security is on the classpath. My biggest concern currently is the heavy use of exceptions to signal declined access as we usually deal with quite a few of these links that translate into proxy invocations and assuming many of those will result in no link added due to insufficient permissions is likely to have a significant performance impact.

Maybe there's a way for Spring Security to provide an API (maybe there even already is) that will rather return an object representing the access decision that's easily checkable?

@odrotbohm odrotbohm changed the title How to use springSecurity into RepresentationModelProcessor for links "filtering" Integrate with SpringSecurity to consider authorization annotations on controller methods. Aug 3, 2020
@odrotbohm odrotbohm changed the title Integrate with SpringSecurity to consider authorization annotations on controller methods. Integrate with SpringSecurity to consider authorization annotations on controller methods Aug 3, 2020
@rwinch
Copy link
Member

rwinch commented Aug 3, 2020

There is not an API on the imperative side that does that. For the reactive side ReactiveAuthorizationManager.check can do it. I created spring-projects/spring-security#8900

@odrotbohm
Copy link
Member

Thanks Rob, appreciated!

@ReDestroyDeR
Copy link

ReDestroyDeR commented Jul 19, 2023

Hello! Is there any updadte regarding this functionality?

I'm researching on this topic for the last 2-3 days and end up here again-and-again

As I understand the general concern is with "post" actions. Semantically speaking, even user won't know if their request will be Forbidden since this decision is made upon inspecting the response, which state can't be predicted from the client.

I understand REST clients the same way frontend treats users. We have a way to saying: "Look! You've got a customer info! I have 3 buttons, that you may press! You can open up a list of orders, edit info or delete profile!". The general point is that he may press them. Would you run an actual method to validate that is this response (not request) forbidden or not? I guess you'd only check if user has some authorities and is allowed to perform said action.

So, as I understand, you don't need a way of predicting the response, because it seems impossible right from the standpoint.

I also have a question regarding "Spring Security Introspection API" that @odrotbohm and @rwinch mentioned. I don't understand how exactly AuthorizationManager<T> relates to the fact, that we need to execute Method Security SPeL using existing Authorization context.

I also don't quite understand a concern about mutability. If we are going to walk though SecurityFilterChain for every Link we are going to add then yes. I think it will not work so nicely. But we already have two facts:

  1. Request has been authorized to access current endpoint
  2. Request has built an authorization context that was used to evaluate permission checking Expressions

And as I understand, these expressions are pure, unless you decided to make one that is not.

I am geniunely interested in a feedback

Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants