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.spring.security.interceptor;
020    
021    import org.apache.shiro.authz.annotation.*;
022    import org.apache.shiro.mgt.SecurityManager;
023    import org.slf4j.Logger;
024    import org.slf4j.LoggerFactory;
025    import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
026    import org.springframework.core.annotation.AnnotationUtils;
027    
028    import java.lang.annotation.Annotation;
029    import java.lang.reflect.Method;
030    
031    
032    /**
033     * TODO - complete JavaDoc
034     *
035     * @since 0.1
036     */
037    @SuppressWarnings({"unchecked"})
038    public class AuthorizationAttributeSourceAdvisor extends StaticMethodMatcherPointcutAdvisor {
039    
040        private static final Logger log = LoggerFactory.getLogger(AuthorizationAttributeSourceAdvisor.class);
041    
042        private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
043                new Class[] {
044                        RequiresPermissions.class, RequiresRoles.class,
045                        RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class
046                };
047    
048        protected SecurityManager securityManager = null;
049    
050        /**
051         * Create a new AuthorizationAttributeSourceAdvisor.
052         */
053        public AuthorizationAttributeSourceAdvisor() {
054            setAdvice(new AopAllianceAnnotationsAuthorizingMethodInterceptor());
055        }
056    
057        public SecurityManager getSecurityManager() {
058            return securityManager;
059        }
060    
061        public void setSecurityManager(org.apache.shiro.mgt.SecurityManager securityManager) {
062            this.securityManager = securityManager;
063        }
064    
065        /**
066         * Returns <tt>true</tt> if the method has any Shiro annotations, false otherwise.
067         * The annotations inspected are:
068         * <ul>
069         * <li>{@link org.apache.shiro.authz.annotation.RequiresAuthentication RequiresAuthentication}</li>
070         * <li>{@link org.apache.shiro.authz.annotation.RequiresUser RequiresUser}</li>
071         * <li>{@link org.apache.shiro.authz.annotation.RequiresGuest RequiresGuest}</li>
072         * <li>{@link org.apache.shiro.authz.annotation.RequiresRoles RequiresRoles}</li>
073         * <li>{@link org.apache.shiro.authz.annotation.RequiresPermissions RequiresPermissions}</li>
074         * </ul>
075         *
076         * @param method      the method to check for a Shiro annotation
077         * @param targetClass the class potentially declaring Shiro annotations
078         * @return <tt>true</tt> if the method has a Shiro annotation, false otherwise.
079         * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, Class)
080         */
081        public boolean matches(Method method, Class targetClass) {
082            Method m = method;
083    
084            if ( isAuthzAnnotationPresent(m) ) {
085                return true;
086            }
087    
088            //The 'method' parameter could be from an interface that doesn't have the annotation.
089            //Check to see if the implementation has it.
090            if ( targetClass != null) {
091                try {
092                    m = targetClass.getMethod(m.getName(), m.getParameterTypes());
093                    if ( isAuthzAnnotationPresent(m) ) {
094                        return true;
095                    }
096                } catch (NoSuchMethodException ignored) {
097                    //default return value is false.  If we can't find the method, then obviously
098                    //there is no annotation, so just use the default return value.
099                }
100            }
101    
102            return false;
103        }
104    
105        private boolean isAuthzAnnotationPresent(Method method) {
106            for( Class<? extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES ) {
107                Annotation a = AnnotationUtils.findAnnotation(method, annClass);
108                if ( a != null ) {
109                    return true;
110                }
111            }
112            return false;
113        }
114    
115    }