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