001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.authroles.authorization.strategies.role.annotations;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.authorization.Action;
021import org.apache.wicket.authroles.authorization.strategies.role.AbstractRoleAuthorizationStrategy;
022import org.apache.wicket.authroles.authorization.strategies.role.IRoleCheckingStrategy;
023import org.apache.wicket.authroles.authorization.strategies.role.Roles;
024import org.apache.wicket.request.component.IRequestableComponent;
025import org.apache.wicket.request.mapper.parameter.PageParameters;
026import org.apache.wicket.request.resource.IResource;
027
028
029/**
030 * Strategy that checks the {@link AuthorizeInstantiation} annotation.
031 * 
032 * @author Eelco Hillenius
033 */
034public class AnnotationsRoleAuthorizationStrategy extends AbstractRoleAuthorizationStrategy
035{
036        /**
037         * Construct.
038         * 
039         * @param roleCheckingStrategy
040         *            the authorizer delegate
041         */
042        public AnnotationsRoleAuthorizationStrategy(final IRoleCheckingStrategy roleCheckingStrategy)
043        {
044                super(roleCheckingStrategy);
045        }
046
047        /**
048         * @see org.apache.wicket.authorization.IAuthorizationStrategy#isInstantiationAuthorized(java.lang.Class)
049         */
050        @Override
051        public <T extends IRequestableComponent> boolean isInstantiationAuthorized(
052                final Class<T> componentClass)
053        {
054                // We are authorized unless we are found not to be
055                boolean authorized = true;
056
057                // Check class annotation first because it is more specific than package annotation
058                final AuthorizeInstantiation classAnnotation = componentClass.getAnnotation(AuthorizeInstantiation.class);
059                if (classAnnotation != null)
060                {
061                        authorized = check(classAnnotation);
062                }
063                else
064                {
065                        // Check package annotation if there is no one on the the class
066                        final Package componentPackage = componentClass.getPackage();
067                        if (componentPackage != null)
068                        {
069                                final AuthorizeInstantiation packageAnnotation = componentPackage.getAnnotation(AuthorizeInstantiation.class);
070                                if (packageAnnotation != null)
071                                {
072                                        authorized = check(packageAnnotation);
073                                }
074                        }
075                }
076
077                // Check for multiple instantiations
078                final AuthorizeInstantiations authorizeInstantiationsAnnotation = componentClass
079                        .getAnnotation(AuthorizeInstantiations.class);
080                if (authorizeInstantiationsAnnotation != null)
081                {
082                        for (final AuthorizeInstantiation authorizeInstantiationAnnotation : authorizeInstantiationsAnnotation
083                                .ruleset())
084                        {
085                                if (!check(authorizeInstantiationAnnotation))
086                                {
087                                        authorized = false;
088                                }
089                        }
090                }
091
092                return authorized;
093        }
094
095        /**
096         * Check if annotated instantiation is allowed.
097         * 
098         * @param authorizeInstantiationAnnotation
099         *            The annotations information
100         * @return False if the instantiation is not authorized
101         */
102        private <T extends IRequestableComponent> boolean check(
103                final AuthorizeInstantiation authorizeInstantiationAnnotation)
104        {
105                // We are authorized unless we are found not to be
106                boolean authorized = true;
107
108                // Check class annotation first because it is more specific than package annotation
109                if (authorizeInstantiationAnnotation != null)
110                {
111                        authorized = hasAny(new Roles(authorizeInstantiationAnnotation.value()));
112                }
113
114                return authorized;
115        }
116        
117        /**
118         * @see org.apache.wicket.authorization.IAuthorizationStrategy#isActionAuthorized(org.apache.wicket.Component,
119         *      org.apache.wicket.authorization.Action)
120         */
121        @Override
122        public boolean isActionAuthorized(final Component component, final Action action)
123        {
124                // Get component's class
125                final Class<?> componentClass = component.getClass();
126
127                return isActionAuthorized(componentClass, action);
128        }
129
130        protected boolean isActionAuthorized(final Class<?> componentClass, final Action action)
131        {
132                // Check for a single action
133                if (!check(action, componentClass.getAnnotation(AuthorizeAction.class)))
134                {
135                        return false;
136                }
137
138                // Check for multiple actions
139                final AuthorizeActions authorizeActionsAnnotation = componentClass.getAnnotation(AuthorizeActions.class);
140                if (authorizeActionsAnnotation != null)
141                {
142                        for (final AuthorizeAction authorizeActionAnnotation : authorizeActionsAnnotation.actions())
143                        {
144                                if (!check(action, authorizeActionAnnotation))
145                                {
146                                        return false;
147                                }
148                        }
149                }
150
151                return true;
152        }
153
154        /**
155         * @param action
156         *            The action to check
157         * @param authorizeActionAnnotation
158         *            The annotations information
159         * @return False if the action is not authorized
160         */
161        private boolean check(final Action action, final AuthorizeAction authorizeActionAnnotation)
162        {
163                if (authorizeActionAnnotation != null)
164                {
165                        if (action.getName().equals(authorizeActionAnnotation.action()))
166                        {
167                                Roles deniedRoles = new Roles(authorizeActionAnnotation.deny());
168                                if (isEmpty(deniedRoles) == false && hasAny(deniedRoles))
169                                {
170                                        return false;
171                                }
172
173                                Roles acceptedRoles = new Roles(authorizeActionAnnotation.roles());
174                                if (!hasAny(acceptedRoles))
175                                {
176                                        return false;
177                                }
178                        }
179                }
180                return true;
181        }
182
183        @Override
184        public boolean isResourceAuthorized(IResource resource, PageParameters pageParameters)
185        {
186                Class<? extends IResource> resourceClass = resource.getClass();
187                boolean allowedByResourceItself = isResourceAnnotationSatisfied(
188                                resourceClass.getAnnotation(AuthorizeResource.class));
189                boolean allowedByPackage = isResourceAnnotationSatisfied(
190                                resourceClass.getPackage().getAnnotation(AuthorizeResource.class));
191                return allowedByResourceItself && allowedByPackage;
192        }
193
194        private boolean isResourceAnnotationSatisfied(AuthorizeResource annotation)
195        {
196                if (annotation != null)
197                {
198                        // we have an annotation => we must check for the required roles
199                        return hasAny(new Roles(annotation.value()));
200                }
201                else
202                {
203                        // no annotation => no required roles => this resource can be accessed
204                        return true;
205                }
206        }
207}