DELTASPIKE-636 restrict duplicated execution of exception-control in case of @Secured + cleanup
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/2af2ccf2 Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/2af2ccf2 Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/2af2ccf2 Branch: refs/heads/master Commit: 2af2ccf250b65c65606b12dd152154b13f1bd6e7 Parents: 1242cec Author: gpetracek <[email protected]> Authored: Thu Jun 12 10:24:59 2014 +0200 Committer: gpetracek <[email protected]> Committed: Thu Jun 12 10:46:11 2014 +0200 ---------------------------------------------------------------------- .../BeforeAccessDeniedExceptionHandler.java | 51 +++++++++++++++ .../SecuredAnnotationAuthorizer.java | 12 ++-- .../SkipInternalProcessingException.java | 38 +++++++++++ .../impl/extension/DefaultSecurityStrategy.java | 69 ++++++++++---------- 4 files changed, 132 insertions(+), 38 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2af2ccf2/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/BeforeAccessDeniedExceptionHandler.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/BeforeAccessDeniedExceptionHandler.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/BeforeAccessDeniedExceptionHandler.java new file mode 100644 index 0000000..e2fc84d --- /dev/null +++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/BeforeAccessDeniedExceptionHandler.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.deltaspike.security.impl.authorization; + +import org.apache.deltaspike.core.api.exception.control.BeforeHandles; +import org.apache.deltaspike.core.api.exception.control.ExceptionHandler; +import org.apache.deltaspike.core.api.exception.control.event.ExceptionEvent; +import org.apache.deltaspike.core.spi.activation.Deactivatable; +import org.apache.deltaspike.core.util.ClassDeactivationUtils; +import org.apache.deltaspike.security.api.authorization.AccessDeniedException; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +@ExceptionHandler +public class BeforeAccessDeniedExceptionHandler implements Deactivatable +{ + protected boolean isActive; + + @PostConstruct + protected void init() + { + this.isActive = ClassDeactivationUtils.isActivated(getClass()); + } + + public void onBeforeAccessDeniedException(@BeforeHandles ExceptionEvent<AccessDeniedException> event) + { + if (!this.isActive) + { + return; + } + event.throwOriginal(); + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2af2ccf2/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java index b192d5b..59746bf 100644 --- a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java +++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SecuredAnnotationAuthorizer.java @@ -144,12 +144,14 @@ public class SecuredAnnotationAuthorizer } AccessDeniedException accessDeniedException = new AccessDeniedException(violations); ExceptionToCatchEvent exceptionToCatchEvent = new ExceptionToCatchEvent(accessDeniedException); - exceptionToCatchEvent.setOptional(true); - this.beanManager.fireEvent(exceptionToCatchEvent); - if (!exceptionToCatchEvent.isHandled()) + try { - throw accessDeniedException; + this.beanManager.fireEvent(exceptionToCatchEvent); + } + catch (AccessDeniedException e) + { + throw new SkipInternalProcessingException(accessDeniedException); } } } @@ -167,4 +169,4 @@ public class SecuredAnnotationAuthorizer } } } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2af2ccf2/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SkipInternalProcessingException.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SkipInternalProcessingException.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SkipInternalProcessingException.java new file mode 100644 index 0000000..e540c68 --- /dev/null +++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/authorization/SkipInternalProcessingException.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.deltaspike.security.impl.authorization; + +import org.apache.deltaspike.security.api.authorization.AccessDeniedException; + +//just to avoid a 2nd call of the handlers +//the first one can't be removed, because we need an active AccessDecisionVoterContext +public class SkipInternalProcessingException extends RuntimeException +{ + private final AccessDeniedException accessDeniedException; + + public SkipInternalProcessingException(AccessDeniedException accessDeniedException) + { + this.accessDeniedException = accessDeniedException; + } + + public AccessDeniedException getAccessDeniedException() + { + return accessDeniedException; + } +} http://git-wip-us.apache.org/repos/asf/deltaspike/blob/2af2ccf2/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/DefaultSecurityStrategy.java ---------------------------------------------------------------------- diff --git a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/DefaultSecurityStrategy.java b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/DefaultSecurityStrategy.java index fac5930..0ef1316 100644 --- a/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/DefaultSecurityStrategy.java +++ b/deltaspike/modules/security/impl/src/main/java/org/apache/deltaspike/security/impl/extension/DefaultSecurityStrategy.java @@ -21,6 +21,7 @@ package org.apache.deltaspike.security.impl.extension; import org.apache.deltaspike.core.api.exception.control.event.ExceptionToCatchEvent; import org.apache.deltaspike.core.util.ProxyUtils; import org.apache.deltaspike.security.api.authorization.AccessDeniedException; +import org.apache.deltaspike.security.impl.authorization.SkipInternalProcessingException; import org.apache.deltaspike.security.spi.authorization.SecurityStrategy; import javax.enterprise.context.Dependent; @@ -58,20 +59,17 @@ public class DefaultSecurityStrategy implements SecurityStrategy Set<Authorizer> authorizers = metaDataStorage.getAuthorizers(targetClass, method); - Object result = null; + invokeBeforeMethodInvocationAuthorizers(invocationContext, authorizers); - if (invokeBeforeMethodInvocationAuthorizers(invocationContext, authorizers)) - { - result = invocationContext.proceed(); + Object result = invocationContext.proceed(); - invokeAfterMethodInvocationAuthorizers(invocationContext, authorizers, result); - } + invokeAfterMethodInvocationAuthorizers(invocationContext, authorizers, result); return result; } - private boolean invokeBeforeMethodInvocationAuthorizers(InvocationContext invocationContext, - Set<Authorizer> authorizers) throws IllegalAccessException + protected void invokeBeforeMethodInvocationAuthorizers( + InvocationContext invocationContext, Set<Authorizer> authorizers) throws IllegalAccessException { try { @@ -83,15 +81,21 @@ public class DefaultSecurityStrategy implements SecurityStrategy } } } - catch (AccessDeniedException ade) + catch (SkipInternalProcessingException e) { - return handleAccessDeniedException(ade); + throw e.getAccessDeniedException(); + } + catch (AccessDeniedException e) + { + RuntimeException exceptionToThrow = handleAccessDeniedException(e); + if (exceptionToThrow != null) + { + throw exceptionToThrow; + } } - - return true; } - private boolean invokeAfterMethodInvocationAuthorizers(InvocationContext invocationContext, + protected void invokeAfterMethodInvocationAuthorizers(InvocationContext invocationContext, Set<Authorizer> authorizers, Object result) throws IllegalAccessException { try @@ -104,38 +108,37 @@ public class DefaultSecurityStrategy implements SecurityStrategy } } } - catch (AccessDeniedException ade) + catch (AccessDeniedException e) { - return handleAccessDeniedException(ade); + RuntimeException exceptionToThrow = handleAccessDeniedException(e); + if (exceptionToThrow != null) + { + throw exceptionToThrow; + } } - - return true; } /** * <p>Fires a {@link org.apache.deltaspike.core.api.exception.control.event.ExceptionToCatchEvent} for the given * {@link org.apache.deltaspike.security.api.authorization.AccessDeniedException}.</p> * - * @param ade The previously thrown exception representing a authorization check failure. - * - * @return False if the processing should be aborted. - * - * @throws org.apache.deltaspike.security.api.authorization.AccessDeniedException - * If the exception was not handled by the application. + * @param originalException exception thrown by an authorizer + * @return the original exception if the default behavior was changed and the exception is unhandled */ - private boolean handleAccessDeniedException(AccessDeniedException ade) throws AccessDeniedException + protected RuntimeException handleAccessDeniedException(AccessDeniedException originalException) { - ExceptionToCatchEvent exceptionToCatchEvent = new ExceptionToCatchEvent(ade); - - exceptionToCatchEvent.setOptional(true); - - beanManager.fireEvent(exceptionToCatchEvent); - + ExceptionToCatchEvent exceptionToCatchEvent = new ExceptionToCatchEvent(originalException); + this.beanManager.fireEvent(exceptionToCatchEvent); + //the next step won't happen per default since ExceptionHandlerBroadcaster will throw the exception, + //because BeforeAccessDeniedExceptionHandler calls #throwOriginal + //but allows to suppress it via deactivating BeforeAccessDeniedExceptionHandler + //(or a 2nd @BeforeHandles method which overrules the default behavior + //(if needed) if (!exceptionToCatchEvent.isHandled()) { - throw ade; + throw originalException; } - return false; + return null; } -} +} \ No newline at end of file
