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
Spring Security Command-level Authorization Interceptors #2983
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some remarks about copyright notices, some about JavaDoc, but also some about potential exceptions and making the introduced interceptors more generic.
In all, I think there's value in this PR, However, let's first discuss what's there before merging.
...ain/java/org/axonframework/spring/authorization/AuthorizationMessageDispatchInterceptor.java
Outdated
Show resolved
Hide resolved
...ain/java/org/axonframework/spring/authorization/AuthorizationMessageDispatchInterceptor.java
Show resolved
Hide resolved
...ng/src/main/java/org/axonframework/spring/authorization/CommandAuthorizationInterceptor.java
Outdated
Show resolved
Hide resolved
spring/src/main/java/org/axonframework/spring/authorization/UnauthorizedCommandException.java
Outdated
Show resolved
Hide resolved
spring/src/test/java/org/axonframework/spring/authorization/AggregateCreatedEvent.java
Show resolved
Hide resolved
* | ||
* @author Roald Bankras | ||
*/ | ||
public class CommandAuthorizationInterceptor implements MessageHandlerInterceptor<CommandMessage<?>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to hear your opinion for this interceptor concerning making it more generic by allowing any Message
. So, a similar change request as I've placed on the AuthorizationMessageDispatchInterceptor
.
If we would make that change, I do think we should rename this class to the MessageAuthorizationInterceptor
.
Or, if we want to be extremely specific, the SpringSecurityAuthorizationInterceptor
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like it, done it!
There might be need for a QueryInterceptorTest.
@Nonnull | ||
@Override | ||
public CommandMessage<?> handle(@Nonnull CommandMessage<?> message) { | ||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a chance any of this might throw a NullPointerException
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getContext()
is guaranteed never null. getAuthentication()
might return null if no authenticatio information is available
...ng/src/main/java/org/axonframework/spring/authorization/CommandAuthorizationInterceptor.java
Outdated
Show resolved
Hide resolved
spring/src/main/java/org/axonframework/spring/authorization/UnauthorizedCommandException.java
Outdated
Show resolved
Hide resolved
public Object handle(UnitOfWork<? extends CommandMessage<?>> unitOfWork, | ||
@javax.annotation.Nonnull InterceptorChain interceptorChain) throws Exception { | ||
CommandMessage<?> command = unitOfWork.getMessage(); | ||
PreAuthorize annotation = command.getPayloadType().getAnnotation(PreAuthorize.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the Class#getAnnotation(Class)
method returns null
if the annotation isn't present.
Perhaps it's good to first check if the annotation is present at all.
You could benefit from the AnnotationUtils
within Axon Framework and, for example, use the AnnotationUtils#isAnnotationPresent(AnnotatedElement, Class)
operation.
If that returns true
, then we can do the validation.
Otherwise, we got a choice to make:
- Throw the unauthorized exception since somebody forgot to add the annotation.
- Simply allow it, as we don't care.
I'm leaning more towards option 1, as somebody would consciously set this interceptor, I believe...
However, there just might be exceptions to the rule for some users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would lean towards 2. While the interceptor is put there on purpose, not all commands/queries require authorization. So the choice becomes:
2.1. Require PreAuthorize annotation on all messages, but without role or with generic role restriction
2.2. Do not require PreAuthorize annotation for messages that do not require authorization.
Co-authored-by: Steven van Beelen <steven.vanbeelen@axoniq.io>
Good to see you back here, @bankras I was wondering if you had considered using a |
I wasn't aware of the option, but it's an interesting one. Surely beats url-pattern authorization. Other paths I've been thinking about since Steven's remark:
|
"No authorities found")); | ||
|
||
log.debug("Authorizing for {} and {}", message.getPayloadType().getName(), annotation.value()); | ||
if (userId.contains(new SimpleGrantedAuthority(annotation.value()))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be adjusted, because 'value' can be a SpEL
Adding interceptors to enable spring-security for command level authorization.
To use these processors in your Axon based application:
AuthorizationMessageDispatchInterceptor
as andispatchInterceptor
on yourCommandGateway
.This will make sure the principals
username
andgrantedAuthorities
are copied from the SecurityContext tot the command messages.CommandAuthorizationInterceptor
as anhandlerInterceptor
on yourCommandBus
. This will verifythe authorities on the command, set by
@PreAuthorize
, with the users granted authorities.