Skip to content

Commit

Permalink
Polish AuthorizationDeniedException Handling
Browse files Browse the repository at this point in the history
Issue gh-14600
  • Loading branch information
jzheaux committed Apr 11, 2024
1 parent b1b84f9 commit 933ef67
Show file tree
Hide file tree
Showing 9 changed files with 18 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* @author Marcus da Coregio
* @since 6.3
*/
public class AuthorizationDeniedException extends AccessDeniedException {
public class AuthorizationDeniedException extends AccessDeniedException implements AuthorizationResult {

private final AuthorizationResult result;

Expand All @@ -40,4 +40,9 @@ public AuthorizationResult getAuthorizationResult() {
return this.result;
}

@Override
public boolean isGranted() {
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
Expand Down Expand Up @@ -190,14 +191,7 @@ private Object attemptAuthorization(MethodInvocation mi, Object result) {
return result;
}

private Object postProcess(MethodInvocationResult mi, AuthorizationDeniedException denied) {
if (this.authorizationManager instanceof MethodAuthorizationDeniedPostProcessor postProcessableDecision) {
return postProcessableDecision.postProcessResult(mi, denied);
}
return this.defaultPostProcessor.postProcessResult(mi, denied);
}

private Object postProcess(MethodInvocationResult mi, AuthorizationDecision decision) {
private Object postProcess(MethodInvocationResult mi, AuthorizationResult decision) {
if (this.authorizationManager instanceof MethodAuthorizationDeniedPostProcessor postProcessableDecision) {
return postProcessableDecision.postProcessResult(mi, decision);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -165,22 +166,7 @@ private Mono<Object> postAuthorize(Mono<Authentication> authentication, MethodIn
});
}

private Mono<Object> postProcess(AuthorizationDeniedException denied,
MethodInvocationResult methodInvocationResult) {
return Mono.fromSupplier(() -> {
if (this.authorizationManager instanceof MethodAuthorizationDeniedPostProcessor postProcessableDecision) {
return postProcessableDecision.postProcessResult(methodInvocationResult, denied);
}
return this.defaultPostProcessor.postProcessResult(methodInvocationResult, denied);
}).flatMap((processedResult) -> {
if (Mono.class.isAssignableFrom(processedResult.getClass())) {
return (Mono<?>) processedResult;
}
return Mono.justOrEmpty(processedResult);
});
}

private Mono<Object> postProcess(AuthorizationDecision decision, MethodInvocationResult methodInvocationResult) {
private Mono<Object> postProcess(AuthorizationResult decision, MethodInvocationResult methodInvocationResult) {
if (decision.isGranted()) {
return Mono.just(methodInvocationResult.getResult());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,6 @@ private Object attemptAuthorization(MethodInvocation mi) throws Throwable {
return mi.proceed();
}

private Object handle(MethodInvocation mi, AuthorizationDeniedException denied) {
if (this.authorizationManager instanceof MethodAuthorizationDeniedHandler handler) {
return handler.handle(mi, denied);
}
return this.defaultHandler.handle(mi, denied);
}

private Object handle(MethodInvocation mi, AuthorizationResult decision) {
if (this.authorizationManager instanceof MethodAuthorizationDeniedHandler handler) {
return handler.handle(mi, decision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -177,21 +178,7 @@ private Mono<Object> preAuthorized(MethodInvocation mi, Mono<Object> mapping) {
});
}

private Mono<Object> postProcess(AuthorizationDeniedException denied, MethodInvocation mi) {
return Mono.fromSupplier(() -> {
if (this.authorizationManager instanceof MethodAuthorizationDeniedHandler handler) {
return handler.handle(mi, denied);
}
return this.defaultHandler.handle(mi, denied);
}).flatMap((processedResult) -> {
if (Mono.class.isAssignableFrom(processedResult.getClass())) {
return (Mono<?>) processedResult;
}
return Mono.justOrEmpty(processedResult);
});
}

private Mono<Object> postProcess(AuthorizationDecision decision, MethodInvocation mi) {
private Mono<Object> postProcess(AuthorizationResult decision, MethodInvocation mi) {
return Mono.fromSupplier(() -> {
if (this.authorizationManager instanceof MethodAuthorizationDeniedHandler handler) {
return handler.handle(mi, decision);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.lang.Nullable;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;

/**
Expand All @@ -44,18 +43,4 @@ public interface MethodAuthorizationDeniedHandler {
@Nullable
Object handle(MethodInvocation methodInvocation, AuthorizationResult authorizationResult);

/**
* Handle denied method invocations, implementations might either throw an
* {@link org.springframework.security.access.AccessDeniedException} or a replacement
* result instead of invoking the method, e.g. a masked value.
* @param methodInvocation the {@link MethodInvocation} related to the authorization
* denied
* @param authorizationDenied the authorization denied exception
* @return a replacement result for the denied method invocation, or null, or a
* {@link reactor.core.publisher.Mono} for reactive applications
*/
default Object handle(MethodInvocation methodInvocation, AuthorizationDeniedException authorizationDenied) {
return handle(methodInvocation, authorizationDenied.getAuthorizationResult());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.springframework.security.authorization.method;

import org.springframework.lang.Nullable;
import org.springframework.security.authorization.AuthorizationDeniedException;
import org.springframework.security.authorization.AuthorizationResult;

/**
Expand All @@ -44,21 +43,4 @@ public interface MethodAuthorizationDeniedPostProcessor {
@Nullable
Object postProcessResult(MethodInvocationResult methodInvocationResult, AuthorizationResult authorizationResult);

/**
* Post-process the denied result produced by a method invocation, implementations
* might either throw an
* {@link org.springframework.security.access.AccessDeniedException} or return a
* replacement result instead of the denied result, e.g. a masked value.
* @param methodInvocationResult the object containing the method invocation and the
* result produced
* @param authorizationDenied the {@link AuthorizationDeniedException} containing the
* authorization denied details
* @return a replacement result for the denied result, or null, or a
* {@link reactor.core.publisher.Mono} for reactive applications
*/
default Object postProcessResult(MethodInvocationResult methodInvocationResult,
AuthorizationDeniedException authorizationDenied) {
return postProcessResult(methodInvocationResult, authorizationDenied.getAuthorizationResult());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ public final class ThrowingMethodAuthorizationDeniedHandler implements MethodAut

@Override
public Object handle(MethodInvocation methodInvocation, AuthorizationResult result) {
if (result instanceof AuthorizationDeniedException denied) {
throw denied;
}
throw new AuthorizationDeniedException("Access Denied", result);
}

@Override
public Object handle(MethodInvocation methodInvocation, AuthorizationDeniedException authorizationDenied) {
throw authorizationDenied;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ public final class ThrowingMethodAuthorizationDeniedPostProcessor implements Met

@Override
public Object postProcessResult(MethodInvocationResult methodInvocationResult, AuthorizationResult result) {
if (result instanceof AuthorizationDeniedException denied) {
throw denied;
}
throw new AuthorizationDeniedException("Access Denied", result);
}

@Override
public Object postProcessResult(MethodInvocationResult methodInvocationResult,
AuthorizationDeniedException authorizationDenied) {
throw authorizationDenied;
}

}

0 comments on commit 933ef67

Please sign in to comment.