001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.authz.aop;
020    
021    import java.util.ArrayList;
022    import java.util.Collection;
023    
024    import org.apache.shiro.aop.MethodInvocation;
025    import org.apache.shiro.authz.AuthorizationException;
026    
027    /**
028     * An <tt>AnnotationsAuthorizingMethodInterceptor</tt> is a MethodInterceptor that asserts a given method is authorized
029     * to execute based on one or more configured <tt>AuthorizingAnnotationMethodInterceptor</tt>s.
030     *
031     * <p>This allows multiple annotations on a method to be processed before the method
032     * executes, and if any of the <tt>AuthorizingAnnotationMethodInterceptor</tt>s indicate that the method should not be
033     * executed, an <tt>AuthorizationException</tt> will be thrown, otherwise the method will be invoked as expected.
034     *
035     * <p>It is essentially a convenience mechanism to allow multiple annotations to be processed in a single method
036     * interceptor.
037     *
038     * @author Les Hazlewood
039     * @since 0.2
040     */
041    public abstract class AnnotationsAuthorizingMethodInterceptor extends AuthorizingMethodInterceptor {
042    
043        /**
044         * The method interceptors to execute for the annotated method.
045         */
046        protected Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors;
047    
048        /**
049         * Default no-argument constructor that defaults the 
050         * {@link #methodInterceptors methodInterceptors} attribute to contain two interceptors by default - the
051         * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and the
052         * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to
053         * support role and permission annotations.
054         */
055        public AnnotationsAuthorizingMethodInterceptor() {
056            methodInterceptors = new ArrayList<AuthorizingAnnotationMethodInterceptor>(5);
057            methodInterceptors.add(new RoleAnnotationMethodInterceptor());
058            methodInterceptors.add(new PermissionAnnotationMethodInterceptor());
059            methodInterceptors.add(new AuthenticatedAnnotationMethodInterceptor());
060            methodInterceptors.add(new UserAnnotationMethodInterceptor());
061            methodInterceptors.add(new GuestAnnotationMethodInterceptor());
062        }
063    
064        /**
065         * Returns the method interceptors to execute for the annotated method.
066         * <p/>
067         * Unless overridden by the {@link #setMethodInterceptors(java.util.Collection)} method, the default collection
068         * contains a
069         * {@link RoleAnnotationMethodInterceptor RoleAnnotationMethodInterceptor} and a
070         * {@link PermissionAnnotationMethodInterceptor PermissionAnnotationMethodInterceptor} to
071         * support role and permission annotations automatically.
072         * @return the method interceptors to execute for the annotated method.
073         */
074        public Collection<AuthorizingAnnotationMethodInterceptor> getMethodInterceptors() {
075            return methodInterceptors;
076        }
077    
078        /**
079         * Sets the method interceptors to execute for the annotated method.
080         * @param methodInterceptors the method interceptors to execute for the annotated method.
081         * @see #getMethodInterceptors()
082         */
083        public void setMethodInterceptors(Collection<AuthorizingAnnotationMethodInterceptor> methodInterceptors) {
084            this.methodInterceptors = methodInterceptors;
085        }
086    
087        /**
088         * Iterates over the internal {@link #getMethodInterceptors() methodInterceptors} collection, and for each one,
089         * ensures that if the interceptor
090         * {@link AuthorizingAnnotationMethodInterceptor#supports(org.apache.shiro.aop.MethodInvocation) supports}
091         * the invocation, that the interceptor
092         * {@link AuthorizingAnnotationMethodInterceptor#assertAuthorized(org.apache.shiro.aop.MethodInvocation) asserts}
093         * that the invocation is authorized to proceed.
094         */
095        protected void assertAuthorized(MethodInvocation methodInvocation) throws AuthorizationException {
096            //default implementation just ensures no deny votes are cast:
097            Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();
098            if (aamis != null && !aamis.isEmpty()) {
099                for (AuthorizingAnnotationMethodInterceptor aami : aamis) {
100                    if (aami.supports(methodInvocation)) {
101                        aami.assertAuthorized(methodInvocation);
102                    }
103                }
104            }
105        }
106    }