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.metadata;
018
019import java.util.HashMap;
020import java.util.Map;
021
022import org.apache.wicket.Component;
023import org.apache.wicket.authroles.authorization.strategies.role.Roles;
024import org.apache.wicket.request.component.IRequestableComponent;
025import org.apache.wicket.util.io.IClusterable;
026
027
028/**
029 * An internal data structure that maps a given component class to a set of role strings.
030 * Permissions can be granted to instantiate a given component class via authorize(Class, Roles
031 * roles) and denied via unauthorize(Class, Roles roles). All authorization can be removed for a
032 * given class with authorizeAll(Class).
033 * 
034 * @author Eelco Hillenius
035 * @author Jonathan Locke
036 */
037public class InstantiationPermissions implements IClusterable
038{
039        private static final long serialVersionUID = 1L;
040
041        /** Holds roles objects for component classes */
042        private final Map<Class<? extends Component>, Roles> rolesForComponentClass = new HashMap<>();
043
044        /**
045         * Gives the given role permission to instantiate the given class.
046         * 
047         * @param <T>
048         * @param componentClass
049         *            The component class
050         * @param rolesToAdd
051         *            The roles to add
052         */
053        public final <T extends Component> void authorize(final Class<T> componentClass,
054                final Roles rolesToAdd)
055        {
056                if (componentClass == null)
057                {
058                        throw new IllegalArgumentException("Argument componentClass cannot be null");
059                }
060
061                if (rolesToAdd == null)
062                {
063                        throw new IllegalArgumentException("Argument rolesToadd cannot be null");
064                }
065
066                Roles roles = rolesForComponentClass.get(componentClass);
067                if (roles == null)
068                {
069                        roles = new Roles();
070                        rolesForComponentClass.put(componentClass, roles);
071                }
072                roles.addAll(rolesToAdd);
073        }
074
075        /**
076         * Gives all roles permission to instantiate the given class. Note that this is only relevant if
077         * a role was previously authorized for that class. If no roles where previously authorized the
078         * effect of the unauthorize call is that no roles at all will be authorized for that class.
079         * 
080         * @param <T>
081         * @param componentClass
082         *            The component class
083         */
084        public final <T extends Component> void authorizeAll(final Class<T> componentClass)
085        {
086                if (componentClass == null)
087                {
088                        throw new IllegalArgumentException("Argument componentClass cannot be null");
089                }
090
091                rolesForComponentClass.remove(componentClass);
092        }
093
094        /**
095         * Gets the roles that have a binding with the given component class.
096         * 
097         * @param <T>
098         * 
099         * @param componentClass
100         *            the component class
101         * @return the roles that have a binding with the given component class, or null if no entries
102         *         are found
103         */
104        public <T extends IRequestableComponent> Roles authorizedRoles(final Class<T> componentClass)
105        {
106                if (componentClass == null)
107                {
108                        throw new IllegalArgumentException("Argument componentClass cannot be null");
109                }
110
111                return rolesForComponentClass.get(componentClass);
112        }
113
114        /**
115         * Removes permission for the given role to instantiate the given class.
116         * 
117         * @param <T>
118         * 
119         * @param componentClass
120         *            The class
121         * @param rolesToRemove
122         *            The role to deny
123         */
124        public final <T extends Component> void unauthorize(final Class<T> componentClass,
125                final Roles rolesToRemove)
126        {
127                if (componentClass == null)
128                {
129                        throw new IllegalArgumentException("Argument componentClass cannot be null");
130                }
131
132                if (rolesToRemove == null)
133                {
134                        throw new IllegalArgumentException("Argument rolesToRemove cannot be null");
135                }
136
137                Roles roles = rolesForComponentClass.get(componentClass);
138                if (roles != null)
139                {
140                        roles.removeAll(rolesToRemove);
141                }
142                else
143                {
144                        roles = new Roles();
145                        rolesForComponentClass.put(componentClass, roles);
146                }
147
148                // If we removed the last authorized role, we authorize the empty role
149                // so that removing authorization can't suddenly open something up to
150                // everyone.
151                if (roles.size() == 0)
152                {
153                        roles.add(MetaDataRoleAuthorizationStrategy.NO_ROLE);
154                }
155        }
156
157        /**
158         * @return gets map with roles objects for a component classes
159         */
160        protected final Map<Class<? extends Component>, Roles> getRolesForComponentClass()
161        {
162                return rolesForComponentClass;
163        }
164}